//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
// software: you can redistribute it and/or modify it under the terms of 
// the GNU General Public License as published by the Free Software Foundation, 
// either version 3 of the License, or (at your option) any later version.

// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
// in the hope that it will be useful, but with permitted additional restrictions 
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
// distributed with this program. You should have received a copy of the 
// GNU General Public License along with permitted additional restrictions 
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection

/* $Header: /CounterStrike/BUILDING.CPP 5     3/13/97 5:18p Joe_b $ */
/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Command & Conquer                                            *
 *                                                                                             *
 *                    File Name : BUILDING.CPP                                                 *
 *                                                                                             *
 *                   Programmer : Joe L. Bostic                                                *
 *                                                                                             *
 *                   Start Date : September 10, 1993                                           *
 *                                                                                             *
 *                  Last Update : October 27, 1996 [JLB]                                       *
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 *   BuildingClass::AI -- Handles non-graphic AI processing for buildings.                     *
 *   BuildingClass::Active_Click_With -- Handles cell selection for buildings.                 *
 *   BuildingClass::Animation_AI -- Handles normal building animation processing.              *
 *   BuildingClass::Assign_Target -- Assigns a target to the building.                         *
 *   BuildingClass::Begin_Mode -- Begins an animation mode for the building.                   *
 *   BuildingClass::BuildingClass -- Constructor for buildings.                                *
 *   BuildingClass::Can_Demolish -- Can the player demolish (sell back) the building?          *
 *   BuildingClass::Can_Enter_Cell -- Determines if building can be placed down.               *
 *   BuildingClass::Can_Fire -- Determines if this building can fire.                          *
 *   BuildingClass::Can_Player_Move -- Can this building be moved?                             *
 *   BuildingClass::Captured -- Captures the building.                                         *
 *   BuildingClass::Center_Coord -- Fetches the center coordinate for the building.            *
 *   BuildingClass::Charging_AI -- Handles the special charging logic for Tesla coils.         *
 *   BuildingClass::Check_Point -- Fetches the landing checkpoint for the given flight pattern.*
 *   BuildingClass::Click_With -- Handles clicking on the map while the building is selected.  *
 *   BuildingClass::Crew_Type -- This determines the crew that this object generates.          *
 *   BuildingClass::Death_Announcement -- Announce the death of this building.                 *
 *   BuildingClass::Debug_Dump -- Displays building status to the monochrome screen.           *
 *   BuildingClass::Detach -- Handles target removal from the game system.                     *
 *   BuildingClass::Detach_All -- Possibly abandons production according to factory type.      *
 *   BuildingClass::Docking_Coord -- Fetches the coordinate to use for docking.                *
 *   BuildingClass::Draw_It -- Displays the building at the location specified.                *
 *   BuildingClass::Drop_Debris -- Drops rubble when building is destroyed.                    *
 *   BuildingClass::Enter_Idle_Mode -- The building will enter its idle mode.                  *
 *   BuildingClass::Exit_Coord -- Determines location where object will leave it.              *
 *   BuildingClass::Exit_Object -- Initiates an object to leave the building.                  *
 *   BuildingClass::Factory_AI -- Handle factory production and initiation.                    *
 *   BuildingClass::Find_Exit_Cell -- Find a clear location to exit an object from this buildin*
 *   BuildingClass::Fire_Direction -- Fetches the direction of firing.                         *
 *   BuildingClass::Fire_Out -- Handles when attached animation expires.                       *
 *   BuildingClass::Flush_For_Placement -- Handles clearing a zone for object placement.       *
 *   BuildingClass::Get_Image_Data -- Fetch the image pointer for the building.                *
 *   BuildingClass::Grand_Opening -- Handles construction completed special operations.        *
 *   BuildingClass::Greatest_Threat -- Searches for target that building can fire upon.        *
 *   BuildingClass::How_Many_Survivors -- This determine the maximum number of survivors.      *
 *   BuildingClass::Init -- Initialize the building system to an empty null state.             *
 *   BuildingClass::Limbo -- Handles power adjustment as building goes into limbo.             *
 *   BuildingClass::Mark -- Building interface to map rendering system.                        *
 *   BuildingClass::Mission_Attack -- Handles attack mission for building.                     *
 *   BuildingClass::Mission_Construction -- Handles mission construction.                      *
 *   BuildingClass::Mission_Deconstruction -- Handles building deconstruction.                 *
 *   BuildingClass::Mission_Guard -- Handles guard mission for combat buildings.               *
 *   BuildingClass::Mission_Harvest -- Handles refinery unloading harvesters.                  *
 *   BuildingClass::Mission_Missile -- State machine for nuclear missile launch.               *
 *   BuildingClass::Mission_Repair -- Handles the repair (active) state for building.          *
 *   BuildingClass::Mission_Unload -- Handles the unload mission for a building.               *
 *   BuildingClass::Pip_Count -- Determines "full" pips to display for building.               *
 *   BuildingClass::Power_Output -- Fetches the current power output from this building.       *
 *   BuildingClass::Read_INI -- Reads buildings from INI file.                                 *
 *   BuildingClass::Receive_Message -- Handle an incoming message to the building.             *
 *   BuildingClass::Remap_Table -- Fetches the remap table to use for this building.           *
 *   BuildingClass::Remove_Gap_Effect -- Stop a gap generator from jamming cells               *
 *   BuildingClass::Repair -- Initiates or terminates the repair process.                      *
 *   BuildingClass::Repair_AI -- Handle the repair (and sell) logic for the building.          *
 *   BuildingClass::Revealed -- Reveals the building to the specified house.                   *
 *   BuildingClass::Rotation_AI -- Process any turret rotation required of this building.      *
 *   BuildingClass::Sell_Back -- Controls the sell back (demolish) operation.                  *
 *   BuildingClass::Shape_Number -- Fetch the shape number for this building.                  *
 *   BuildingClass::Sort_Y -- Returns the building coordinate used for sorting.                *
 *   BuildingClass::Take_Damage -- Inflicts damage points upon a building.                     *
 *   BuildingClass::Target_Coord -- Return the coordinate to use when firing on this building. *
 *   BuildingClass::Toggle_Primary -- Toggles the primary factory state.                       *
 *   BuildingClass::Turret_Facing -- Fetches the turret facing for this building.              *
 *   BuildingClass::Unlimbo -- Removes a building from limbo state.                            *
 *   BuildingClass::Update_Buildables -- Informs sidebar of additional construction options.   *
 *   BuildingClass::Value -- Determine the value of this building.                             *
 *   BuildingClass::What_Action -- Determines action to perform if click on specified object.  *
 *   BuildingClass::What_Action -- Determines what action will occur.                          *
 *   BuildingClass::Write_INI -- Write out the building data to the INI file specified.        *
 *   BuildingClass::delete -- Deallocates building object.                                     *
 *   BuildingClass::new -- Allocates a building object from building pool.                     *
 *   BuildingClass::~BuildingClass -- Destructor for building type objects.                    *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include	"function.h"

/*
** New sidebar for GlyphX multiplayer. ST - 8/2/2019 2:35PM
*/
#include "SidebarGlyphx.h"

enum SAMState {
	SAM_READY,					// Launcher can be facing any direction tracking targets.
	SAM_FIRING					// Stationary while missile is being fired.
};


/***************************************************************************
**	Center of building offset table.
*/
COORDINATE const BuildingClass::CenterOffset[BSIZE_COUNT] = {
	0x00800080L,
	0x008000FFL,
	0x00FF0080L,
	0x00FF00FFL,
	0x018000FFL,
	0x00FF0180L,
	0x01800180L,

	0x00FF0200L,

	0x02800280L,
};


/***********************************************************************************************
 * BuildingClass::Receive_Message -- Handle an incoming message to the building.               *
 *                                                                                             *
 *    This routine handles an incoming message to the building. Messages regulate the          *
 *    various cooperative ventures between buildings and units. This might include such        *
 *    actions as coordinating the construction yard animation with the actual building's       *
 *    construction animation.                                                                  *
 *                                                                                             *
 * INPUT:   from     -- The originator of the message received.                                *
 *                                                                                             *
 *          message  -- The radio message received.                                            *
 *                                                                                             *
 *          param    -- Reference to an optional parameter that might be used to return        *
 *                      extra information to the message originator.                           *
 *                                                                                             *
 * OUTPUT:  Returns with the response to the message (typically, this is just RADIO_OK).       *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/09/1994 JLB : Created.                                                                 *
 *   06/26/1995 JLB : Forces refinery load anim to start immediately.                          *
 *   08/13/1995 JLB : Uses ScenarioInit for special loose "CAN_LOAD" check.                    *
 *=============================================================================================*/
RadioMessageType BuildingClass::Receive_Message(RadioClass * from, RadioMessageType message, long & param)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	switch (message) {

		/*
		**	This message is received as a request to attach/load/dock with this building.
		**	Verify that this is allowed and return the appropriate response.
		*/
		case RADIO_CAN_LOAD:
			TechnoClass::Receive_Message(from, message, param);
			if (!House->Is_Ally(from)) return(RADIO_STATIC);
			if (Mission == MISSION_CONSTRUCTION || Mission == MISSION_DECONSTRUCTION || BState == BSTATE_CONSTRUCTION || (!ScenarioInit && Class->Type != STRUCT_REFINERY && In_Radio_Contact())) return(RADIO_NEGATIVE);
			switch (Class->Type) {
				case STRUCT_AIRSTRIP:
					if (from->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass const *)from)->Class->IsFixedWing) {
						return(RADIO_ROGER);
					}
					break;

				case STRUCT_HELIPAD:
					if (from->What_Am_I() == RTTI_AIRCRAFT && !((AircraftClass const *)from)->Class->IsFixedWing) {
						return(RADIO_ROGER);
					}
					break;

				case STRUCT_REPAIR:
					if (from->What_Am_I() == RTTI_UNIT || (from->What_Am_I() == RTTI_AIRCRAFT)) {
						if (Transmit_Message(RADIO_ON_DEPOT, from) != RADIO_ROGER) {
							return(RADIO_ROGER);
						}
					}
					return(RADIO_NEGATIVE);

				case STRUCT_REFINERY:
					if (from->What_Am_I() == RTTI_UNIT &&
						*((UnitClass *)from) == UNIT_HARVESTER &&
						(ScenarioInit || !Is_Something_Attached())) {

						return((Contact_With_Whom() != from) ? RADIO_ROGER : RADIO_NEGATIVE);
					}
					break;

				default:
					break;
			}
			return(RADIO_STATIC);

		/*
		**	This message is received when the object has attached itself to this
		**	building.
		*/
		case RADIO_IM_IN:
			if (Mission == MISSION_DECONSTRUCTION) {
				return(RADIO_NEGATIVE);
			}
			switch (Class->Type) {
				case STRUCT_REPAIR:
					IsReadyToCommence = true;
					Assign_Mission(MISSION_REPAIR);
					from->Assign_Mission(MISSION_SLEEP);
					return(RADIO_ROGER);

				case STRUCT_AIRSTRIP:
				case STRUCT_HELIPAD:
					Assign_Mission(MISSION_REPAIR);
					from->Assign_Mission(MISSION_SLEEP);
					return(RADIO_ROGER);

				case STRUCT_REFINERY:
					Mark(MARK_CHANGE);
					from->Assign_Mission(MISSION_UNLOAD);
					return(RADIO_ROGER);

				default:
					break;
			}
			break;

		/*
		**	Docking maneuver maintenance message. See if new order should be given to the
		**	unit trying to dock.
		*/
		case RADIO_DOCKING:
			TechnoClass::Receive_Message(from, message, param);

			/*
			**	When in radio contact for loading, the refinery starts
			**	flashing the lights.
			*/
			if (*this == STRUCT_REFINERY && BState != BSTATE_FULL) {
				Begin_Mode(BSTATE_FULL);
			}

			/*
			**	If this building is already in radio contact, then it might
			**	be able to satisfy the request to load by bumping off any
			**	preoccupying task.
			*/
			if (*this == STRUCT_REPAIR) {
				if (Contact_With_Whom() != from) {
					if (Transmit_Message(RADIO_ON_DEPOT) == RADIO_ROGER) {
						if (Transmit_Message(RADIO_NEED_REPAIR) == RADIO_NEGATIVE) {
							Transmit_Message(RADIO_RUN_AWAY);
							Transmit_Message(RADIO_OVER_OUT);
							return(RADIO_ROGER);
						}
					}
				}
			}

			/*
			**	Establish contact with the object if this building isn't already in contact
			**	with another.
			*/
			if (!In_Radio_Contact()) {
				Transmit_Message(RADIO_HELLO, from);
			}

			if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
				switch (Class->Type) {
					case STRUCT_AIRSTRIP:
						param = As_Target();
						break;

					case STRUCT_HELIPAD:
						param = As_Target();
						break;

					case STRUCT_REPAIR:
						Transmit_Message(RADIO_TETHER);
						param = ::As_Target(Coord_Cell(Center_Coord()));
						break;

					case STRUCT_REFINERY:
						param = ::As_Target(Coord_Cell(Adjacent_Cell(Center_Coord(), DIR_S)));
						break;
				}

				/*
				**	Tell the harvester to move to the docking pad of the building.
				*/
				if (Transmit_Message(RADIO_MOVE_HERE, param) == RADIO_YEA_NOW_WHAT) {

					/*
					**	Since the harvester is already there, tell it to begin the backup
					**	procedure now. If it can't, then tell it to get outta here.
					*/
					Transmit_Message(RADIO_TETHER);
					if (*this == STRUCT_REFINERY && Transmit_Message(RADIO_BACKUP_NOW, from) != RADIO_ROGER) {
						from->Scatter(NULL, true, true);
					}
				}
			}
			return(RADIO_ROGER);

		/*
		**	If a transport or harvester is requesting permission to head toward, dock
		**	and load/unload, check to make sure that this is allowed given the current
		**	state of the building.
		*/
		case RADIO_ARE_REFINERY:
			if (Is_Something_Attached() || In_Radio_Contact() || IsInLimbo || House->Class->House != from->Owner() || (*this != STRUCT_REFINERY/* && *this != STRUCT_REPAIR*/)) {
				return(RADIO_NEGATIVE);
			}
			return(RADIO_ROGER);

		/*
		**	Someone is telling us that it is starting construction. This should only
		**	occur if this is a construction yard and a building was just placed on
		**	the map.
		*/
		case RADIO_BUILDING:
			Assign_Mission(MISSION_REPAIR);
			TechnoClass::Receive_Message(from, message, param);
			return(RADIO_ROGER);

		/*
		**	Someone is telling us that they have finished construction. This should
		**	only occur if this is a construction yard and the building that was being
		**	constructed has finished. In this case, stop the construction yard
		**	animation.
		*/
		case RADIO_COMPLETE:
			if (Mission != MISSION_DECONSTRUCTION) {
				Assign_Mission(MISSION_GUARD);
			}
			TechnoClass::Receive_Message(from, message, param);
			return(RADIO_ROGER);

		/*
		**	This message may occur unexpectedly if the unit in contact with this
		**	building is suddenly destroyed. Handle any cleanup necessary. For example,
		**	a construction yard should stop its construction animation in this case.
		*/
		case RADIO_OVER_OUT:
			Begin_Mode(BSTATE_IDLE);
			if (*this == STRUCT_REPAIR) {
				Assign_Mission(MISSION_GUARD);
			}
			TechnoClass::Receive_Message(from, message, param);
			return(RADIO_ROGER);

		/*
		**	This message is received when an object has completely left
		** building. Sometimes special cleanup action is required when
		**	this event occurs.
		*/
		case RADIO_UNLOADED:
			if (*this == STRUCT_REPAIR) {
				if (Distance(from) < 0x0180) {
					return(RADIO_ROGER);
				}
			}
			TechnoClass::Receive_Message(from, message, param);
			if (*this == STRUCT_WEAP || *this == STRUCT_AIRSTRIP || *this == STRUCT_REPAIR) return(RADIO_RUN_AWAY);
			return(RADIO_ROGER);

		default:
			break;
	}

	/*
	**	Pass along the message to the default message handler in the radio itself.
	*/
	return(TechnoClass::Receive_Message(from, message, param));
}


#ifdef CHEAT_KEYS
/***********************************************************************************************
 * BuildingClass::Debug_Dump -- Displays building status to the monochrome screen.             *
 *                                                                                             *
 *    This utility function will output the current status of the building class to the        *
 *    monochrome screen. It is through this data that bugs may be fixed or detected.           *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/31/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Debug_Dump(MonoClass * mono) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	mono->Set_Cursor(0, 0);
	mono->Print(Text_String(TXT_DEBUG_BUILDING));
	mono->Fill_Attrib(66, 13, 12, 1, IsRepairing ? MonoClass::INVERSE : MonoClass::NORMAL);
	mono->Fill_Attrib(66, 14, 12, 1, IsToRebuild ? MonoClass::INVERSE : MonoClass::NORMAL);
	mono->Fill_Attrib(66, 15, 12, 1, IsAllowedToSell ? MonoClass::INVERSE : MonoClass::NORMAL);
	mono->Fill_Attrib(66, 16, 12, 1, IsCharging ? MonoClass::INVERSE : MonoClass::NORMAL);
	mono->Fill_Attrib(66, 17, 12, 1, IsCharged ? MonoClass::INVERSE : MonoClass::NORMAL);
	mono->Fill_Attrib(66, 18, 12, 1, IsJamming ? MonoClass::INVERSE : MonoClass::NORMAL);
	mono->Fill_Attrib(66, 19, 12, 1, IsJammed ? MonoClass::INVERSE : MonoClass::NORMAL);

	mono->Set_Cursor(1, 11);
	if (Factory) {
		mono->Printf("%s %d%%", Factory->Get_Object()->Class_Of().IniName, (100*Factory->Completion())/FactoryClass::STEP_COUNT);
	}

	TechnoClass::Debug_Dump(mono);
}
#endif


/***********************************************************************************************
 * BuildingClass::Draw_It -- Displays the building at the location specified.                  *
 *                                                                                             *
 *    This is the low level graphic routine that displays the building at the location         *
 *    specified.                                                                               *
 *                                                                                             *
 * INPUT:   x,y   -- The coordinate to draw the building at.                                   *
 *                                                                                             *
 *          window   -- The clipping window to use.                                            *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/20/1994 JLB : Created.                                                                 *
 *   06/27/1994 JLB : Takes a clipping window parameter.                                       *
 *   07/06/1995 JLB : Handles damaged silos correctly.                                         *
 *=============================================================================================*/
void BuildingClass::Draw_It(int x, int y, WindowNumberType window) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	/*
	**	The shape file to use for rendering depends on whether the building
	**	is undergoing construction or not.
	*/
	void const * shapefile = Get_Image_Data();
	if (shapefile == NULL) return;

	/*
	**	Actually draw the building shape.
	*/
	IsTheaterShape = Class->IsTheater;	//Let Build_Frame know if this is a theater specific shape
	Techno_Draw_Object(shapefile, Shape_Number(), x, y, window);
	IsTheaterShape = false;

	/*
	** Patch for adding overlay onto weapon factory.  Only add the overlay if
	** the building has more than 1 hp.  Also, if the building's in radio
	** contact, he must be unloading a constructed vehicle, so draw that
	** vehicle before drawing the overlay.
	*/
	if (BState != BSTATE_CONSTRUCTION) {

		/*
		**	A Tethered object is always rendered AFTER the building.
		*/
		if (*this == STRUCT_WEAP && IsTethered && In_Radio_Contact() && !Contact_With_Whom()->IsInLimbo && Contact_With_Whom()->What_Am_I() != RTTI_BUILDING) {
			TechnoClass * contact = Contact_With_Whom();

			assert(contact->IsActive);
			int xxx = x + ((int)Lepton_To_Pixel((int)Coord_X(contact->Render_Coord())) - (int)Lepton_To_Pixel((int)Coord_X(Render_Coord())));
			int yyy = y + ((int)Lepton_To_Pixel((int)Coord_Y(contact->Render_Coord())) - (int)Lepton_To_Pixel((int)Coord_Y(Render_Coord())));
			contact->Draw_It(xxx, yyy, window);
			contact->IsToDisplay = false;
		}

		/*
		**	Draw the weapon factory custom overlay graphic.
		*/
		if ( (*this == STRUCT_WEAP || *this == STRUCT_FAKEWEAP)) {
			int shapenum = Door_Stage();
			if (Health_Ratio() <= Rule.ConditionYellow) shapenum += 4;
			// Added override shape file name. ST - 8/1/2019 5:24PM
			//Techno_Draw_Object(Class->WarFactoryOverlay, shapenum, x, y, window);
			Techno_Draw_Object_Virtual(Class->WarFactoryOverlay, shapenum, x, y, window, DIR_N, 0x0100, "WEAP2");
		}

		/*
		**	Draw any repair feedback graphic required.
		*/
		if (IsRepairing && IsWrenchVisible) {
			CC_Draw_Shape(ObjectTypeClass::SelectShapes, SELECT_WRENCH, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL);
		}
	}

	TechnoClass::Draw_It(x, y, window);

	/*
	** If this is a factory that we're spying on, show what it's producing
	*/
	if ((Spied_By() & (1<<(PlayerPtr->Class->House)) && Is_Selected_By_Player()) || ((window == WINDOW_VIRTUAL) && (Session.Type != GAME_NORMAL))) {

		/*
		**	Fetch the factory that is associate with this building. For computer controlled buildings, the
		**	factory pointer is integral to the building itself. For human controlled buildings, the factory
		**	pointer is part of the house structure and must be retrieved from there.
		*/
		FactoryClass * factory = NULL;
		if (House->IsHuman) {
			factory = House->Fetch_Factory(Class->ToBuild);
		} else {
			factory = Factory;
		}

		/*
		**	If there is a factory associated with this building, then fetch any attached
		**	object under production and display its cameo image over the top of this building.
		*/
		if (factory != NULL) {
			TechnoClass * obj = factory->Get_Object();
			if (obj != NULL) {
#ifdef FIXIT_CSII
				CC_Draw_Shape(obj, obj->Techno_Type_Class()->Get_Cameo_Data(), 0, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL|SHAPE_NORMAL, NULL);
#else
				void const * remapper = obj->House->Remap_Table(false, obj->Techno_Type_Class()->Remap);
				CC_Draw_Shape(obj->Techno_Type_Class()->Get_Cameo_Data(), 0, x, y, window, SHAPE_CENTER|SHAPE_WIN_REL | ((remapper != NULL) ? SHAPE_FADING : SHAPE_NORMAL), remapper);
#endif
			}
		}
	}
}


/***********************************************************************************************
 * BuildingClass::Shape_Number -- Fetch the shape number for this building.                    *
 *                                                                                             *
 *    This routine will examine the current state of the building and return with the shape    *
 *    number to use. The shape number is subordinate to the building graphic image data.       *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the shape number to use when rendering this building.                 *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
int BuildingClass::Shape_Number(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	int shapenum = Fetch_Stage();

	/*
	**	The shape file to use for rendering depends on whether the building
	**	is undergoing construction or not.
	*/
	if (BState == BSTATE_CONSTRUCTION) {

		/*
		**	If the building is deconstructing, then the display frame progresses
		**	from the end to the beginning. Reverse the shape number accordingly.
		*/
		if (Mission == MISSION_DECONSTRUCTION) {
			shapenum = (Class->Anims[BState].Start+Class->Anims[BState].Count-1)-shapenum;
		}

	} else {

		/*
		**	If this is a camouflaged pill box and it is not owned by the player, then
		**	it is displayed with the MEGA-camouflaged imagery.
		*/
		if ((!IsOwnedByPlayer) && (*this == STRUCT_CAMOPILLBOX)) {
			shapenum += 1;
		}

		/*
		**	The Tesla Coil has a stage value that can be overridden by
		**	its current state.
		*/
		if (*this == STRUCT_TESLA) {
			if (IsCharged) {
				shapenum = 3;
			} else {
				if (IsCharging) {
					shapenum = Fetch_Stage();
				} else {
					shapenum = 0;
				}
			}
		}

		/*
		**	Buildings that contain a turret handle their shape determination
		**	differently than normal buildings. They need to take into consideration
		**	the direction the turret is facing.
		*/
		if (Class->IsTurretEquipped) {
			shapenum = UnitClass::BodyShape[Dir_To_32(PrimaryFacing.Current())];

			if (*this == STRUCT_SAM) {

				/*
				**	SAM sites that are free to rotate fetch their animation frame
				**	from the building's turret facing. All other animation stages
				**	fetch their frame from the embedded animation sequencer.
				*/
//				if (Status == SAM_READY || Status == SAM_FIRING || Status == SAM_LOCKING) {
//					shapenum = Fetch_Stage();
//				}
				if (Health_Ratio() <= Rule.ConditionYellow) {
					shapenum += 35;
				}
			} else {
				if (IsInRecoilState) {
					shapenum += 32;
				}
				if (Health_Ratio() <= Rule.ConditionYellow) {
					shapenum += 64;
				}
			}
		} else {

			/*
			**	If it is a significantly damaged weapons factory, it is shown in
			**	the worst state possible.
			*/
			if (*this == STRUCT_WEAP || *this == STRUCT_FAKEWEAP) {
				shapenum = 0;
				if (Health_Ratio() <= Rule.ConditionYellow) {
					shapenum = 1;
				}

			} else {

				/*
				**	Special render stage for silos. The stage is dependent on the current
				**	Tiberium collected as it relates to Tiberium capacity.
				*/
				if (*this == STRUCT_STORAGE) {

					int level = 0;
					if (House->Capacity) {
						level = (House->Tiberium * 5) / House->Capacity;
					}

					shapenum += Bound(level, 0, 4);
					if (Health_Ratio() <= Rule.ConditionYellow) {
						shapenum += 5;
					}

				} else {

					/*
					**	If below half strenth, then show the damage frames of the
					**	building.
					*/
					if (Health_Ratio() <= Rule.ConditionYellow) {
						if (*this == STRUCT_CHRONOSPHERE) {
							shapenum += 29;
						} else {
							int last1 = Class->Anims[BSTATE_IDLE].Start + Class->Anims[BSTATE_IDLE].Count;
							int last2 = Class->Anims[BSTATE_ACTIVE].Start + Class->Anims[BSTATE_ACTIVE].Count;
							int largest = max(last1, last2);
							last2 = Class->Anims[BSTATE_AUX1].Start + Class->Anims[BSTATE_AUX1].Count;
							largest = max(largest, last2);
							last2 = Class->Anims[BSTATE_AUX2].Start + Class->Anims[BSTATE_AUX2].Count;
							largest = max(largest, last2);
							shapenum += largest;
						}
					}
				}
			}
		}
	}
	return(shapenum);
}


/***********************************************************************************************
 * BuildingClass::Mark -- Building interface to map rendering system.                          *
 *                                                                                             *
 *    This routine is used to mark the map cells so that when it renders                       *
 *    the underlying icons will also be updated as necessary.                                  *
 *                                                                                             *
 * INPUT:   mark  -- Type of image change (MARK_UP, _DOWN, _CHANGE)                            *
 *             MARK_UP  -- Building is removed.                                                *
 *             MARK_CHANGE -- Building changes shape.                                          *
 *             MARK_DOWN -- Building is added.                                                 *
 *                                                                                             *
 * OUTPUT:  bool; Did the mark operation succeed? Failure could be the result of marking down  *
 *                when the building is already marked down, or visa versa.                     *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   03/31/1994 JLB : Created.                                                                 *
 *   04/15/1994 JLB : Converted to member function.                                            *
 *   04/16/1994 JLB : Added health bar tracking.                                               *
 *   12/23/1994 JLB : Calls low level check before proceeding.                                 *
 *   01/27/1995 JLB : Special road spacer template added.                                      *
 *=============================================================================================*/
bool BuildingClass::Mark(MarkType mark)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (TechnoClass::Mark(mark)) {
		short const * offset = Overlap_List();
		short const * occupy = Occupy_List();
		CELL cell = Coord_Cell(Coord);
		SmudgeType bib;

		switch (mark) {
			case MARK_UP:
				Map.Pick_Up(cell, this);
				if (Class->Bib_And_Offset(bib, cell)) {
					SmudgeClass * smudge = new SmudgeClass(bib);
					if (smudge != NULL) {
						smudge->Disown(cell);
						delete smudge;
					}
				}
				break;

			case MARK_DOWN:

				/*
				**	Special wall logic is handled here. A building that is really a wall
				**	gets converted into an overlay wall type when it is placed down. The
				**	actual building object itself is destroyed.
				*/
				if (Class->IsWall) {
					switch (Class->Type) {
						case STRUCT_BRICK_WALL:
							new OverlayClass(OVERLAY_BRICK_WALL, cell, House->Class->House);
							break;

						case STRUCT_BARBWIRE_WALL:
							new OverlayClass(OVERLAY_BARBWIRE_WALL, cell, House->Class->House);
							break;

						case STRUCT_SANDBAG_WALL:
							new OverlayClass(OVERLAY_SANDBAG_WALL, cell, House->Class->House);
							break;

						case STRUCT_WOOD_WALL:
							new OverlayClass(OVERLAY_WOOD_WALL, cell, House->Class->House);
							break;

						case STRUCT_CYCLONE_WALL:
							new OverlayClass(OVERLAY_CYCLONE_WALL, cell, House->Class->House);
							break;

						case STRUCT_FENCE:
							new OverlayClass(OVERLAY_FENCE, cell, House->Class->House);
							break;

						default:
							break;
					}
					Transmit_Message(RADIO_OVER_OUT);
					delete this;

				} else {
					if (Can_Enter_Cell(cell) == MOVE_OK) {
						/*
						**	Determine if a bib is required for this building. If one is, then
						**	create and place it.
						*/
						CELL newcell = cell;
						if (Class->Bib_And_Offset(bib, newcell)) {
							new SmudgeClass(bib, Cell_Coord(newcell), Class->IsBase ? House->Class->House : HOUSE_NONE);
						}

						Map.Place_Down(cell, this);
					} else {
						return(false);
					}
				}
				break;

			case MARK_CHANGE_REDRAW:
				Map.Refresh_Cells(cell, Overlap_List(true));
				break;

			default:
				Map.Refresh_Cells(cell, Overlap_List(false));
				Map.Refresh_Cells(cell, occupy);
				break;
		}
		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * BuildingClass::AI -- Handles non-graphic AI processing for buildings.                       *
 *                                                                                             *
 *    This function is to handle the AI logic for the building. The graphic logic (facing,     *
 *    firing, and animation) is handled elsewhere.                                             *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/31/1994 JLB : Created.                                                                 *
 *   12/26/1994 JLB : Handles production.                                                      *
 *   06/11/1995 JLB : Revamped.                                                                *
 *=============================================================================================*/
void BuildingClass::AI(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	/*
	**	Process building animation state changes. Transition to a following state
	**	if there is one specified and the current animation sequence has expired.
	**	This process must occur before mission AI since the mission AI relies on
	**	the bstate change to occur immediately before the MissionClass::AI.
	*/
	Animation_AI();

	/*
	**	If now is a good time to act on a new mission, then do so. This process occurs
	**	here because some outside event may have requested a mission change for the building.
	**	Such outside requests (player input) must be initiated BEFORE the normal AI process.
	*/
	if (IsReadyToCommence && BState != BSTATE_CONSTRUCTION) {

		/*
		**	Clear the commencement flag ONLY if something actually occurred. By acting
		**	this way, a building can set the IsReadyToCommence flag before it goes
		**	to "sleep" knowing that it will wake up as soon as a new mission comes
		**	along.
		*/
		if (Commence()) {
			IsReadyToCommence = false;
		}
	}

	/*
	**	Proceed with normal logic processing. This is where the mission processing
	**	occurs. This call must be located after the animation sequence makes the
	**	transition to the next frame (see above) in order for the mission logic to
	**	act at the exact moment of graphic transition BEFORE it has a chance to
	**	be displayed.
	*/
	TechnoClass::AI();

	/*
	**	Bail if the object died in the AI routine.
	*/
	if (!IsActive) {
		return;
	}

	/*
	**	Building ammo is instantly reloaded.
	*/
	if (!Ammo) {
		Ammo = Class->MaxAmmo;
	}

	/*
	**	If now is a good time to act on a new mission, then do so. This occurs here because
	**	some AI event may have requested a mission change (usually from another mission
	**	state machine). This must occur here before it has a chance to render.
	*/
	if (IsReadyToCommence) {

		/*
		**	Clear the commencement flag ONLY if something actually occurred. By acting
		**	this way, a building can set the IsReadyToCommence flag before it goes
		**	to "sleep" knowing that it will wake up as soon as a new mission comes
		**	along.
		*/
		if (Commence()) {
			IsReadyToCommence = false;
		}
	}

	/*
	**	If a change of animation was requested, then make the change
	**	now. The building animation system acts independently but subordinate
	**	to the mission state machine system. By performing the animation change-up
	**	here, the mission AI system is ensured of immediate visual affect when it
	**	decides to change the animation state of the building.
	*/
	if (QueueBState != BSTATE_NONE) {
		if (BState != QueueBState) {
			BState = QueueBState;
			BuildingTypeClass::AnimControlType const * ctrl = Fetch_Anim_Control();
			if (BState == BSTATE_CONSTRUCTION || BState == BSTATE_IDLE) {
				Set_Rate(Options.Normalize_Delay(ctrl->Rate));
			} else {
				Set_Rate(ctrl->Rate);
			}
			Set_Stage(ctrl->Start);
		}
		QueueBState = BSTATE_NONE;
	}

	/*
	**	If the building's strength has changed, then update the power
	**	accordingly.
	*/
	if (Strength != LastStrength) {
		int oldpower = Power_Output();
		LastStrength = Strength;
		int newpower = Power_Output();
		House->Adjust_Power(newpower - oldpower);
	}

	/*
	**	Check to see if the destruction countdown timer is active. If so, then decrement it.
	**	When this timer reaches zero, the building is removed from the map. All the explosions
	**	are presumed to be in progress at this time.
	*/
	if (Strength == 0) {
		if (CountDown == 0) {
			Limbo();
			Drop_Debris(WhomToRepay);
			delete this;
		}
		return;
	}

	/*
	**	Charging logic.
	*/
	Charging_AI();

	/*
	**	Handle any repair process that may be going on.
	*/
	Repair_AI();

	/*
	**	For computer controlled buildings, determine what should be produced and start
	**	production accordingly.
	*/
	Factory_AI();

	/*
	**	Check for demolition timeout. When timeout has expired, the building explodes.
	*/
	if (IsGoingToBlow && CountDown == 0) {

		/*
		** Maybe trigger an achivement. ST - 11/14/2019 1:53PM
		*/
		TechnoTypeClass const *object_type = Techno_Type_Class();
		if (object_type) {
			TechnoClass *saboteur = As_Techno(WhomToRepay);
			if (saboteur && saboteur->IsActive && saboteur->House && saboteur->House->IsHuman) {
				On_Achievement_Event(saboteur->House, "BUILDING_DESTROYED_C4", object_type->IniName);
			}
		}			
		
		int damage = Strength;
		Take_Damage(damage, 0, WARHEAD_FIRE, As_Techno(WhomToRepay), true);
		if (!IsActive) {
			return;
		}
		Mark(MARK_CHANGE);
	}

	/*
	**	Turret equiped buildings must handle turret rotation logic here. This entails
	**	rotating the turret to the desired facing as well as figuring out what that
	**	desired facing should be.
	*/
	Rotation_AI();

	/*
	** Gap Generators need to scan if they've just become activated, or if
	** the power has just come on enough so they can scan.  Also, they need
	** to un-jam if the power has just dropped off.
	*/
	if (*this == STRUCT_GAP) {
		if (Arm == 0) {
			IsJamming = false;
			Arm = TICKS_PER_MINUTE * Rule.GapRegenInterval + Random_Pick(1, TICKS_PER_SECOND);
		}

		if (!IsJamming) {
			if (House->Power_Fraction() >= 1) {
				Map.Jam_From(Coord_Cell(Center_Coord()), Rule.GapShroudRadius, House);
				IsJamming = true;
			}
		} else {
			if (House->Power_Fraction() < 1) {
				IsJamming = false;
				Map.UnJam_From(Coord_Cell(Center_Coord()), Rule.GapShroudRadius, House);
			}
		}
	}

	/*
	** Radar facilities and SAMs need to check for the proximity of a mobile
	** radar jammer.
	*/
	if ((*this == STRUCT_RADAR || *this == STRUCT_SAM) && (Frame % TICKS_PER_SECOND) == 0) {
		IsJammed = false;
		for (int index = 0; index < Units.Count(); index++) {
			UnitClass * obj = Units.Ptr(index);
			if (obj != NULL &&
					!obj->IsInLimbo &&
					!obj->House->Is_Ally(House) &&
					obj->Class->IsJammer &&
					Distance(obj) <= Rule.RadarJamRadius) {

				IsJammed = true;
				break;
			}
		}
	}

	/*
	** Chronosphere active animation control.
	*/
	if (*this == STRUCT_CHRONOSPHERE && BState == BSTATE_ACTIVE && QueueBState == BSTATE_NONE && Scen.FadeTimer == 0) {
		Begin_Mode(BSTATE_IDLE);
	}
}


/***********************************************************************************************
 * BuildingClass::Unlimbo -- Removes a building from limbo state.                              *
 *                                                                                             *
 *    Use this routine to transform a building that has been held in limbo                     *
 *    state, into one that really exists on the map. Once a building as                        *
 *    been unlimboed, then it becomes a normal object in the game world.                       *
 *                                                                                             *
 * INPUT:   pos   -- The position to place the building on the map.                            *
 *                                                                                             *
 *          dir (optional) -- not used for this class                                          *
 *                                                                                             *
 * OUTPUT:  bool; Was the unlimbo successful?                                                  *
 *                                                                                             *
 * WARNINGS:   The unlimbo operation might not be successful if the                            *
 *             building could not be placed at the location specified.                         *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   04/16/1994 JLB : Created.                                                                 *
 *   06/07/1994 JLB : Matches virtual function format for base class.                          *
 *   05/09/1995 JLB : Handles wall placement.                                                  *
 *   06/18/1995 JLB : Checks for wall legality before placing down.                            *
 *=============================================================================================*/
bool BuildingClass::Unlimbo(COORDINATE coord, DirType dir)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	/*
	**	If this is a wall type building, then it never gets unlimboed. Instead, it gets
	**	converted to an overlay type.
	*/
	if (Class->IsWall) {
		if (Can_Enter_Cell(Coord_Cell(coord), FACING_NONE) == MOVE_OK) {
			OverlayType otype = OVERLAY_NONE;
			switch (Class->Type) {
				case STRUCT_SANDBAG_WALL:
					otype	= OVERLAY_SANDBAG_WALL;
					break;

				case STRUCT_CYCLONE_WALL:
					otype = OVERLAY_CYCLONE_WALL;
					break;

				case STRUCT_BRICK_WALL:
					otype = OVERLAY_BRICK_WALL;
					break;

				case STRUCT_BARBWIRE_WALL:
					otype = OVERLAY_BARBWIRE_WALL;
					break;

				case STRUCT_WOOD_WALL:
					otype = OVERLAY_WOOD_WALL;
					break;

				case STRUCT_FENCE:
					otype = OVERLAY_FENCE;
					break;

				default:
					otype = OVERLAY_NONE;
					break;

			}
			if (otype != OVERLAY_NONE) {
				ObjectClass * o = OverlayTypeClass::As_Reference(otype).Create_One_Of(House);
				if (o && o->Unlimbo(coord)) {
					Map[coord].Owner = House->Class->House;
					Transmit_Message(RADIO_OVER_OUT);
					Map.Sight_From(Coord_Cell(coord), Class->SightRange, House);
					delete this;
					return(true);
				}
			}
		}
		return(false);
	}

	/*
	**	Normal building unlimbo process.
	*/
	if (TechnoClass::Unlimbo(coord, dir)) {

		/*
		**	Ensure that the owning house knows about the
		**	new object.
		*/
		House->BScan |= (1L << Class->Type);
		House->ActiveBScan |= (1L << Class->Type);

		/*
		**	Recalculate the center point of the house's base.
		*/
		House->Recalc_Center();

		/*
		**	Update the total factory type, assuming this building has a factory.
		*/
		House->Active_Add(this);

		/*
		**	Possibly the sidebar will be affected by this addition.
		*/
		House->IsRecalcNeeded = true;
		LastStrength = 0;

		// Changes to support client/server multiplayer. ST - 8/2/2019 2:36PM
		//if ((!IsDiscoveredByPlayer && Map[coord].IsVisible) || Session.Type != GAME_NORMAL) {
		if ((!Is_Discovered_By_Player(House) && Map[coord].Is_Visible(House)) || Session.Type != GAME_NORMAL) {
			if (House->IsHuman) {
				//Revealed(PlayerPtr);
				Revealed(House);
			}
		}
		if (!House->IsHuman) {
			Revealed(House);
		}

		// Changes to support client/server multiplayer. ST - 8/2/2019 2:36PM
		//if (IsOwnedByPlayer) {
		if (Is_Owned_By_Player()) {
			Map.PowerClass::IsToRedraw = true;
			Map.Flag_To_Redraw(false);
		}

		if ((Class->Ownable & (HOUSEF_GOOD | HOUSEF_BAD)) != (HOUSEF_GOOD | HOUSEF_BAD)) {
			if (Class->Ownable & HOUSEF_GOOD) {
				ActLike = HOUSE_GREECE;
			} else {
				ActLike = HOUSE_USSR;
			}
		}

		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * BuildingClass::Take_Damage -- Inflicts damage points upon a building.                       *
 *                                                                                             *
 *    This routine will inflict damage points upon the specified building.                     *
 *    It will handle the damage animation and building destruction. Use                        *
 *    this routine whenever a building is attacked.                                            *
 *                                                                                             *
 * INPUT:   damage   -- Amount of damage to inflict.                                           *
 *                                                                                             *
 *          distance -- The distance from the damage center point to the object's center point.*
 *                                                                                             *
 *          warhead  -- The kind of damage to inflict.                                         *
 *                                                                                             *
 *          source   -- The source of the damage. This is used to change targeting.            *
 *                                                                                             *
 *          forced   -- Is the damage forced upon the object regardless of whether it          *
 *                      is normally immune?                                                    *
 *                                                                                             *
 * OUTPUT:  true/false; Was the building destroyed?                                            *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/21/1991     : Created.                                                                 *
 *   04/15/1994 JLB : Converted to member function.                                            *
 *   04/16/1994 JLB : Added warhead modifier to damage.                                        *
 *   06/03/1994 JLB : Added source of damage as target value.                                  *
 *   06/20/1994 JLB : Source is a base class pointer.                                          *
 *   11/22/1994 JLB : Shares base damage handler for techno objects.                           *
 *   07/15/1995 JLB : Power ratio gets adjusted.                                               *
 *=============================================================================================*/
ResultType BuildingClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source, bool forced)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	ResultType res = RESULT_NONE;
	int shakes;

	if (this != source /*&& !Class->IsInsignificant*/) {

		if (source) {
			House->LATime = Frame;
			House->LAType = source->What_Am_I();
			House->LAZone = House->Which_Zone(this);
			House->LAEnemy = source->Owner();

			if (!House->Is_Ally(source)) {
				House->Enemy = source->Owner();
			}

			Base_Is_Attacked(source);
		}

		short const * offset = Occupy_List();

		/*
		** Memorize who they used to be in radio contact with.
		*/
		TechnoClass *tech = Contact_With_Whom();
		/*
		**	Perform the low level damage assessment.
		*/
		res = TechnoClass::Take_Damage(damage, distance, warhead, source, forced);
		switch (res) {
			case RESULT_DESTROYED:

				/*
				**	Add the building to the base prebuild list if allowed. This will force
				**	the computer to rebuild this structure if it can.
				*/
				if (IsToRebuild && Class->Level != -1 && Base.House == House->Class->House && Base.Get_Node(this) == 0) {
//				if (IsToRebuild && Class->IsBuildable && Base.House == House->Class->House && Base.Get_Node(this) == 0) {
					Base.Nodes.Add(BaseNodeClass(Class->Type, Coord_Cell(Coord)));
				}

				/*
				**	Destroy all attached objects.
				*/
				while (Attached_Object()) {
					FootClass * obj = Detach_Object();

					Detach_All(true);
					delete obj;
				}

				/*
				** If we were in contact with a landed plane, blow the plane up too.
				*/
				if (tech && tech->IsActive && tech->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass *)tech)->Class->IsFixedWing && ((AircraftClass *)tech)->In_Which_Layer() == LAYER_GROUND) {
					int damage = 500;
					tech->Take_Damage(damage, 0, WARHEAD_AP, source, forced);
				}

				Sound_Effect(VOC_KABOOM22, Coord);
				while (*offset != REFRESH_EOL) {
					CELL cell = Coord_Cell(Coord) + *offset++;

					/*
					**	If the building is destroyed, then lots of
					**	explosions occur.
					*/
					new SmudgeClass(Random_Pick(SMUDGE_CRATER1, SMUDGE_CRATER6), Cell_Coord(cell));
					if (Percent_Chance(50)) {
						new AnimClass(ANIM_FIRE_SMALL, Coord_Scatter(Cell_Coord(cell), 0x0080), Random_Pick(0, 7), Random_Pick(1, 3));
						if (Percent_Chance(50)) {
							new AnimClass(ANIM_FIRE_MED, Coord_Scatter(Cell_Coord(cell), 0x0040), Random_Pick(0, 7), Random_Pick(1, 3));
						}
					}
					new AnimClass(ANIM_FBALL1, Coord_Scatter(Cell_Coord(cell), 0x0040), Random_Pick(0, 3));
				}

				shakes = Class->Cost_Of() / 400;
				if (shakes) {
					Shake_The_Screen(shakes, Owner());
					if (source && Owner() != source->Owner()) {
						Shake_The_Screen(shakes, source->Owner());
					}
				}
				Sound_Effect(VOC_CRUMBLE, Coord);
				if (Mission == MISSION_DECONSTRUCTION) {
					CountDown = 0;
					Set_Rate(0);
				} else {
					CountDown = 8;
				}

				/*
				**	If it is in radio contact and the object seems to be attached, then tell
				**	it to run away.
				*/
				if (In_Radio_Contact() && Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
					Transmit_Message(RADIO_RUN_AWAY);
				}

				/*
				**	A force destruction will not generate survivors.
				*/
				if (forced || *this == STRUCT_KENNEL) {
					IsSurvivorless = true;
				}

				/*
				** Destruction of a radar facility or advanced communications
				** center will cause the spiedby field to change...
				*/
				if (SpiedBy) {
					SpiedBy = 0;
					StructType struc = *this;
					if (struc == STRUCT_RADAR /* || struc == STRUCT_EYE */) {
						Update_Radar_Spied();
					}
				}

				/*
				** Destruction of a gap generator will cause the cells it affects
				** to stop being jammed.
				*/
				if (*this == STRUCT_GAP) {
					Remove_Gap_Effect();
				}

				/*
				** Destruction of a shipyard or sub pen may cause attached ships
				** who are repairing themselves to discontinue repairs.
				*/
				if (*this == STRUCT_SHIP_YARD || *this == STRUCT_SUB_PEN) {
					for (int index = 0; index < Vessels.Count(); index++) {
						VesselClass *obj = Vessels.Ptr(index);
						if (obj && !obj->IsInLimbo && obj->House == House) {
							if (obj->IsSelfRepairing) {
								if (::Distance(Center_Coord(), obj->Center_Coord()) < 0x0200) {
									obj->IsSelfRepairing = false;
									obj->IsToSelfRepair = false;
								}
							}
						}
					}
				}

				/*
				** Destruction of a barrel will cause the surrounding squares to
				** be hit with damage.
				*/
				if (*this == STRUCT_BARREL || *this == STRUCT_BARREL3) {
					COORDINATE center = Center_Coord();
					CELL cellcenter = Coord_Cell(center);

					BulletClass * bullet;

					bullet = new BulletClass(BULLET_INVISIBLE, ::As_Target(Adjacent_Cell(cellcenter, FACING_N)), 0, 200, WARHEAD_FIRE, MPH_MEDIUM_FAST);
					if (bullet) {
						bullet->Unlimbo(center, DIR_N);
					}

					bullet = new BulletClass(BULLET_INVISIBLE, ::As_Target(Adjacent_Cell(cellcenter, FACING_E)), 0, 200, WARHEAD_FIRE, MPH_MEDIUM_FAST);
					if (bullet) {
						bullet->Unlimbo(center, DIR_E);
					}

					bullet = new BulletClass(BULLET_INVISIBLE, ::As_Target(Adjacent_Cell(cellcenter, FACING_S)), 0, 200, WARHEAD_FIRE, MPH_MEDIUM_FAST);
					if (bullet) {
						bullet->Unlimbo(center, DIR_S);
					}

					bullet = new BulletClass(BULLET_INVISIBLE, ::As_Target(Adjacent_Cell(cellcenter, FACING_W)), 0, 200, WARHEAD_FIRE, MPH_MEDIUM_FAST);
					if (bullet) {
						bullet->Unlimbo(center, DIR_W);
					}
				}

				if (House) {
					House->Check_Pertinent_Structures();
				}

				break;

			case RESULT_HALF:
				if (*this == STRUCT_PUMP) {
					AnimClass * anim = new AnimClass(ANIM_OILFIELD_BURN, Coord_Add(Coord, 0x00400130L), 1);
					if (anim) {
						anim->Attach_To(this);
					}
				}
				// Fall into next case.

			case RESULT_MAJOR:
				Sound_Effect(VOC_KABOOM1, Coord);
				while (*offset != REFRESH_EOL) {
					CELL cell = Coord_Cell(Coord) + *offset++;
					AnimClass * anim = NULL;

					/*
					**	Show pieces of fire to indicate that a significant change in
					**	damage level has occurred.
					*/
					if (warhead == WARHEAD_FIRE) {
						switch (Random_Pick(0, 5+Class->Width()+Class->Height())) {
							case 0:
								break;

							case 1:
							case 2:
							case 3:
							case 4:
							case 5:
								anim = new AnimClass(ANIM_ON_FIRE_SMALL, Coord_Scatter(Cell_Coord(cell), 0x0060), 0, Random_Pick(1, 3));
								break;

							case 6:
							case 7:
							case 8:
								anim = new AnimClass(ANIM_ON_FIRE_MED, Coord_Scatter(Cell_Coord(cell), 0x0060), 0, Random_Pick(1, 3));
								break;

							case 9:
								anim = new AnimClass(ANIM_ON_FIRE_BIG, Coord_Scatter(Cell_Coord(cell), 0x0060), 0, 1);
								break;

							default:
								break;
						}
					} else {
						if (Percent_Chance(50)) {
							/*
							** Building may catch on fire, but only if it wasn't a
							** renovator that caused the damage.
							*/
							if (source == NULL || source->What_Am_I() != RTTI_INFANTRY || *(InfantryClass *)source != INFANTRY_RENOVATOR) {
								anim = new AnimClass(ANIM_FIRE_SMALL, Coord_Scatter(Cell_Coord(cell), 0x0060), Random_Pick(0, 7), Random_Pick(1, 3));
							}
						}
					}
					/*
					**	If the animation was created, then attach it to the building.
					*/
					if (anim) {
						anim->Attach_To(this);
					}
				}
				break;

			case RESULT_NONE:
				break;

			case RESULT_LIGHT:
				break;
		}

		if (source && res != RESULT_NONE) {

			/*
			**	If any damage occurred, then inform the house of this fact. If it is the player's
			**	house, it might announce this fact.
			*/
			if (!Class->IsInsignificant) {
				House->Attacked(this);
			}

			/*
			** Save the type of the house that's doing the damage, so if the building burns
			** to death credit can still be given for the kill
			*/
			WhoLastHurtMe = source->Owner();

			/*
			**	When certain buildings are hit, they "snap out of it" and
			**	return fire if they are able and allowed.
			*/
			if (*this != STRUCT_SAM && *this != STRUCT_AAGUN &&
				!House->Is_Ally(source) &&
				Class->PrimaryWeapon != NULL &&
				(!Target_Legal(TarCom) || !In_Range(TarCom))) {

				if (source->What_Am_I() != RTTI_AIRCRAFT && (!House->IsHuman || Rule.IsSmartDefense)) {
					Assign_Target(source->As_Target());
				} else {

					/*
					**	Generate a random rotation effect since there is nothing else that this
					**	building can do.
					*/
					if (!PrimaryFacing.Is_Rotating()) {
						PrimaryFacing.Set_Desired(Random_Pick(DIR_N, DIR_MAX));
					}
				}
			}
		}
	}

	return(res);
}


/***********************************************************************************************
 * BuildingClass::new -- Allocates a building object from building pool.                       *
 *                                                                                             *
 *    This routine will allocate a building slot from the building alloc                       *
 *    system.                                                                                  *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with a pointer to the allocated building. If NULL is                       *
 *          returned, then this indicates a failure to allocate.                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   04/11/1994 JLB : Created.                                                                 *
 *   04/21/1994 JLB : Converted to operator new.                                               *
 *   05/17/1994 JLB : Revamped allocation scheme                                               *
 *   07/29/1994 JLB : Simplified.                                                              *
 *=============================================================================================*/
void * BuildingClass::operator new(size_t )
{
	void * ptr = Buildings.Allocate();
	if (ptr) {
		((BuildingClass *)ptr)->Set_Active();
	}
	return(ptr);
}


/***********************************************************************************************
 * BuildingClass::delete -- Deallocates building object.                                       *
 *                                                                                             *
 *    This is the memory deallocation operation for a building object.                         *
 *    Since buildings are allocated out of a fixed memory block, all that                      *
 *    is needed is to flag the unit as inactive.                                               *
 *                                                                                             *
 * INPUT:   ptr   -- Pointer to building to deallocate.                                        *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   04/21/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::operator delete(void *ptr)
{
	if (ptr) {
		((BuildingClass *)ptr)->IsActive = false;
	}
	Buildings.Free((BuildingClass *)ptr);
}


/***********************************************************************************************
 * BuildingClass::BuildingClass -- Constructor for buildings.                                  *
 *                                                                                             *
 *    This routine inserts a building into the object tracking system.                         *
 *    It is placed into a limbo state unless a location is provided for                        *
 *    it to unlimbo at.                                                                        *
 *                                                                                             *
 * INPUT:   type  -- The structure type to make this object.                                   *
 *                                                                                             *
 *          house -- The owner of this building.                                               *
 *                                                                                             *
 *          pos   -- The position to unlimbo the building. If -1 is                            *
 *                   specified, then the building remains in a limbo                           *
 *                   state.                                                                    *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   04/21/1994 JLB : Created.                                                                 *
 *   08/07/1995 JLB : Fixed act like value to match expected value.                            *
 *=============================================================================================*/
BuildingClass::BuildingClass(StructType type, HousesType house) :
	TechnoClass(RTTI_BUILDING, Buildings.ID(this), house),
	Class(BuildingTypes.Ptr((int)type)),
	Factory(0),
	ActLike(House->ActLike),
	IsToRebuild(false),
	IsToRepair(false),
	IsAllowedToSell(true),
	IsReadyToCommence(false),
	IsRepairing(false),
	IsWrenchVisible(false),
	IsGoingToBlow(false),
	IsSurvivorless(false),
	IsCharging(false),
	IsCharged(false),
	IsCaptured(false),
	IsJamming(false),
	IsJammed(false),
	HasFired(false),
	HasOpened(false),
	CountDown(0),
	BState(BSTATE_NONE),
	QueueBState(BSTATE_NONE),
	WhoLastHurtMe(house),
	WhomToRepay(TARGET_NONE),
	AnimToTrack(TARGET_NONE),
	LastStrength(0),
	PlacementDelay(0)
{
	House->Tracking_Add(this);
	IsSecondShot = !Class->Is_Two_Shooter();
	Strength = Class->MaxStrength;
	Ammo = Class->MaxAmmo;

	/*
	**	If the building could never be built, then it can never be sold either. This
	**	is due to the lack of buildup animation.
	*/
	if (Class->Get_Buildup_Data() != NULL) {
//	if (!Class->IsBuildable) {
		IsAllowedToSell = false;
	}

//	if (Session.Type == GAME_INTERNET) {
//		House->BuildingTotals->Increment_Unit_Total( (int) type);
//	}

}


/***********************************************************************************************
 * BuildingClass::~BuildingClass -- Destructor for building type objects.                      *
 *                                                                                             *
 *    This destructor for building objects will put the building in limbo if possible.         *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/18/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
BuildingClass::~BuildingClass(void)
{
	if (GameActive && Class) {
		if (House) {
			House->Tracking_Remove(this);
		}
		BuildingClass::Limbo();
	}
	Class = 0;

	delete (FactoryClass *)Factory;
	Factory = 0;
	ID = -1;
}


/***********************************************************************************************
 * BuildingClass::Drop_Debris -- Drops rubble when building is destroyed.                      *
 *                                                                                             *
 *    This routine is called when a building is destroyed. It handles                          *
 *    placing the rubble down.                                                                 *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/14/1994 JLB : Created.                                                                 *
 *   06/13/1995 JLB : Added smoke and normal infantry survivor possibility.                    *
 *   07/16/1995 JLB : Survival rate depends on if captured or sabotaged.                       *
 *=============================================================================================*/
void BuildingClass::Drop_Debris(TARGET source)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	CELL const * offset;
	CELL cell;

	/*
	**	Generate random survivors from the destroyed building.
	*/
	cell = Coord_Cell(Coord);
	offset = Occupy_List();
	int odds = 2;
	if (Target_Legal(WhomToRepay)) odds -= 1;
	if (IsCaptured) odds += 6;
	int count = How_Many_Survivors();
	while (*offset != REFRESH_EOL) {
		CELL	newcell;

		newcell = cell + *offset++;
		CellClass const * cellptr = &Map[newcell];

		/*
		**	Infantry could run out of a destroyed building.
		*/
		if (!House->IsToDie && count > 0) {
			InfantryClass * i = NULL;

			if (Random_Pick(0, odds) == 1) {
				i = NULL;
				InfantryType typ = Crew_Type();
				if (typ != INFANTRY_NONE) i = new InfantryClass(typ, House->Class->House);
				if (i != NULL) {
					if (Class->Get_Buildup_Data() != NULL && i->Class->IsNominal) i->IsTechnician = true;
					ScenarioInit++;
					if (i->Unlimbo(Cell_Coord(newcell), DIR_N)) {
						count--;
						i->Strength = Random_Pick(5, (int)i->Class->MaxStrength);
						i->Scatter(0, true);
						if (source != TARGET_NONE && !House->Is_Ally(As_Object(source))) {
							i->Assign_Mission(MISSION_ATTACK);
							i->Assign_Target(source);
						} else {
							if (House->IsHuman) {
								i->Assign_Mission(MISSION_GUARD);
							} else {
								i->Assign_Mission(MISSION_HUNT);
							}
						}
					} else {
						delete i;
					}
					ScenarioInit--;
				}
			}
		}

		/*
		**	Smoke and fire only appear on terrestrail cells. They should not appear on
		**	rivers, clifs, or water cells.
		*/
		if (cellptr->Is_Clear_To_Move(SPEED_TRACK, true, true)) {

			/*
			**	Possibly add some smoke rising from the ashes of the building.
			*/
			switch (Random_Pick(0, 5)) {
				case 0:
				case 1:
				case 2:
					new AnimClass(ANIM_SMOKE_M, Coord_Scatter(Cell_Coord(newcell), 0x0050, false), Random_Pick(0, 5), Random_Pick(1, 2));
					break;

				default:
					break;
			}

			/*
			**	The building always scars the ground in some fashion.
			*/
			if (Percent_Chance(25)) {
				new SmudgeClass(Random_Pick(SMUDGE_SCORCH1, SMUDGE_SCORCH6), Cell_Coord(newcell));
			} else {
				new SmudgeClass(Random_Pick(SMUDGE_CRATER1, SMUDGE_CRATER6), Coord_Scatter(Cell_Coord(newcell), 0x0080, false));
			}
		}
	}
}


/***********************************************************************************************
 * BuildingClass::Active_Click_With -- Handles clicking on the map while the building is selected.*
 *                                                                                             *
 *    This interface routine handles when the player clicks on the map while this building     *
 *    is currently selected. This is used to assign an override target to a turret or          *
 *    guard tower.                                                                             *
 *                                                                                             *
 * INPUT:   target   -- The target that was clicked upon.                                      *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/28/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Active_Click_With(ActionType action, ObjectClass * object)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (action == ACTION_ATTACK && object != NULL) {
		Player_Assign_Mission(MISSION_ATTACK, object->As_Target());
	}

	if (action == ACTION_TOGGLE_PRIMARY && Class->Is_Factory()) {
		OutList.Add(EventClass(EventClass::PRIMARY, TargetClass(this)));
	}
}


/***********************************************************************************************
 * BuildingClass::Active_Click_With -- Handles cell selection for buildings.                   *
 *                                                                                             *
 *    This routine really only serves one purpose -- to allow targeting of the ground for      *
 *    buildings that are equipped with weapons.                                                *
 *                                                                                             *
 * INPUT:   action   -- The requested action to perform.                                       *
 *                                                                                             *
 *          cell     -- The cell location to perform the action upon.                          *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/04/1995 JLB : Created.                                                                 *
 *   10/04/1995 JLB : Handles construction yard undeploy to move logic.                        *
 *=============================================================================================*/
void BuildingClass::Active_Click_With(ActionType action, CELL cell)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (action == ACTION_ATTACK) {
		Player_Assign_Mission(MISSION_ATTACK, ::As_Target(cell));
	}

	if (action == ACTION_MOVE && *this == STRUCT_CONST) {
		OutList.Add(EventClass(EventClass::ARCHIVE, TargetClass(this), TargetClass(::As_Target(cell))));
		OutList.Add(EventClass(EventClass::SELL, TargetClass(this)));

		COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
		OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord, 1 << PlayerPtr->Class->House));
	}
}


/***********************************************************************************************
 * BuildingClass::Assign_Target -- Assigns a target to the building.                           *
 *                                                                                             *
 *    Assigning of a target to a building makes sense if the building is one that can attack.  *
 *    This routine would be used to assign the attack target to a turret or guard tower.       *
 *                                                                                             *
 * INPUT:   target   -- The target that was clicked on while this building was selected.       *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/28/1994 JLB : Created.                                                                 *
 *   11/02/1994 JLB : Checks for range before assigning target.                                *
 *=============================================================================================*/
void BuildingClass::Assign_Target(TARGET target)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (*this != STRUCT_SAM && *this != STRUCT_AAGUN && !In_Range(target, 0)) {
		target = TARGET_NONE;
	}

	TechnoClass::Assign_Target(target);
}


/***********************************************************************************************
 * BuildingClass::Init -- Initialize the building system to an empty null state.               *
 *                                                                                             *
 *    This routine initializes the building system in preparation for a scenario load.         *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   09/19/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Init(void)
{
	Buildings.Free_All();
}


/***********************************************************************************************
 * BuildingClass::Exit_Object -- Initiates an object to leave the building.                    *
 *                                                                                             *
 *    This function is used to cause an object to exit the building. It is called when a       *
 *    factory produces a vehicle or other mobile object and that object needs to exit the      *
 *    building to join the ranks of a regular unit. Typically, the object is placed down on    *
 *    the map such that it overlaps the building and then it is given a movement order so that *
 *    it will move to an adjacent free cell.                                                   *
 *                                                                                             *
 * INPUT:   base  -- Pointer to the object that is to exit the building.                       *
 *                                                                                             *
 * OUTPUT:  Returns the success rating for the exit attempt;                                   *
 *             0  = complete failure (refund money please)                                     *
 *             1  = temporarily prevented (try again later please)                             *
 *             2  = successful                                                                 *
 *                                                                                             *
 * WARNINGS:   The building is placed in radio contact with the object. The object is in a     *
 *             tethered condition. This condition will be automatically broken when the        *
 *             object reaches the adjacent square.                                             *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   11/28/1994 JLB : Created.                                                                 *
 *   04/10/1995 JLB : Handles building production by computer.                                 *
 *   06/17/1995 JLB : Handles refinery exit.                                                   *
 *=============================================================================================*/
int BuildingClass::Exit_Object(TechnoClass * base)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (!base) return(0);

	TechnoTypeClass const * ttype = (TechnoTypeClass const *)&base->Class_Of();

	/*
	**	A unit exiting a building is always considered to be "locked". That means, it
	**	will be considered as to have legally entered the visible map domain.
	*/
	base->IsLocked = true;

	/*
	**	Find a good cell to unload the object to. The object, probably a vehicle
	**	will drive/walk to the adjacent free cell.
	*/
	CELL cell = 0;

	switch (base->What_Am_I()) {

		case RTTI_AIRCRAFT:
			if (!In_Radio_Contact()) {
				AircraftClass * air = (AircraftClass *)base;

				air->Height = 0;
				ScenarioInit++;
				if (air->Unlimbo(Docking_Coord(), air->Pose_Dir())) {
					Transmit_Message(RADIO_HELLO, air);
					Transmit_Message(RADIO_TETHER);
					ScenarioInit--;
					return(2);
				}
				ScenarioInit--;
			} else {
				AircraftClass * air = (AircraftClass *)base;

				if (Cell_X(Coord_Cell(Center_Coord())) - Map.MapCellX < Map.MapCellWidth/2) {
					cell = XY_Cell(Map.MapCellX-1, Random_Pick(0, Map.MapCellHeight-1)+Map.MapCellY);
				} else {
					cell = XY_Cell(Map.MapCellX+Map.MapCellWidth, Random_Pick(0, Map.MapCellHeight-1)+Map.MapCellY);
				}
				ScenarioInit++;
				if (air->Unlimbo(Cell_Coord(cell), DIR_N)) {
//BG				air->Assign_Destination(::As_Target(Nearby_Location(air)));
/*BG*/			air->Assign_Destination(::As_Target(air->Nearby_Location(this)));
					air->Assign_Mission(MISSION_MOVE);
					ScenarioInit--;
					return(2);
				}
				ScenarioInit--;
			}
			break;

		case RTTI_VESSEL:
			switch (Class->Type) {
				case STRUCT_SUB_PEN:
				case STRUCT_SHIP_YARD:
					ScenarioInit++;
					cell = Find_Exit_Cell(base);
					if (cell != 0 && base->Unlimbo(Cell_Coord(cell), Direction(Cell_Coord(cell)))) {
						base->Assign_Mission(MISSION_GUARD);
						ScenarioInit--;
						return(2);
					}
					ScenarioInit--;
					break;

				default:
					break;
			}
			break;

		case RTTI_INFANTRY:
		case RTTI_UNIT:
			switch (Class->Type) {
				case STRUCT_REFINERY:
					if (base->What_Am_I() == RTTI_UNIT) {
						cell = Coord_Cell(Center_Coord());
						UnitClass * unit = (UnitClass *)base;

						cell = Adjacent_Cell(cell, FACING_SW);
						ScenarioInit++;
						if (unit->Unlimbo(Cell_Coord(Adjacent_Cell(cell, DIR_S)), DIR_SW_X2)) {
							unit->PrimaryFacing = DIR_S;
							unit->Assign_Mission(MISSION_HARVEST);
						}
						ScenarioInit--;
					} else {
						base->Scatter(0, true);
					}
					break;

				case STRUCT_WEAP:
					if (Mission == MISSION_UNLOAD) {
						for(int index = 0; index < Buildings.Count(); index++) {
							BuildingClass *bldg = Buildings.Ptr(index);
							if (bldg->Owner() == Owner() && *bldg == STRUCT_WEAP && bldg != this && bldg->Mission == MISSION_GUARD && !bldg->Factory) {
								FactoryClass * temp = Factory;
								bldg->Factory = Factory;
								Factory = 0;
								int retval = (bldg->Exit_Object(base));
								bldg->Factory = 0;
								Factory = temp;
								return(retval);
							}
						}
						return(1);	// fail while we're still unloading previous
					}
					ScenarioInit++;
					if (base->Unlimbo(Exit_Coord(), DIR_S)) {
						base->Mark(MARK_UP);
						base->Coord = Exit_Coord();
						base->Mark(MARK_DOWN);
						Transmit_Message(RADIO_HELLO, base);
						Transmit_Message(RADIO_TETHER);
						Assign_Mission(MISSION_UNLOAD);
						ScenarioInit--;
						return(2);
					}
					ScenarioInit--;
					break;

				case STRUCT_BARRACKS:
				case STRUCT_TENT:
				case STRUCT_KENNEL:

					cell = Find_Exit_Cell(base);
					if (cell != 0) {
						DirType	dir = Direction(cell);
						COORDINATE		start = Exit_Coord();

						ScenarioInit++;
						if (base->Unlimbo(start, dir)) {

							base->Assign_Mission(MISSION_MOVE);

							/*
							**	When disembarking from a transport then guard an area around the
							**	center of the base.
							*/
							base->Assign_Destination(::As_Target(cell));
							if (House->IQ >= Rule.IQGuardArea) {
								base->Assign_Mission(MISSION_GUARD_AREA);
								base->ArchiveTarget = ::As_Target(House->Where_To_Go((FootClass *)base));
							}

							/*
							**	Establish radio contact so unload coordination can occur. This
							**	radio contact should always succeed.
							*/
							if (Transmit_Message(RADIO_HELLO, base) == RADIO_ROGER) {
								Transmit_Message(RADIO_UNLOAD);
							}
							ScenarioInit--;
							return(2);
						}
						ScenarioInit--;
					}
					break;

				default:
					cell = Find_Exit_Cell(base);
					if (cell != 0) {
						DirType	dir = Direction(cell);
						COORDINATE		start = Exit_Coord();

						ScenarioInit++;
						if (base->Unlimbo(start, dir)) {

							base->Assign_Mission(MISSION_MOVE);

							/*
							**	When disembarking from a transport then guard an area around the
							**	center of the base.
							*/
							base->Assign_Destination(::As_Target(cell));
							if (House->IQ >= Rule.IQGuardArea) {
								base->Assign_Mission(MISSION_GUARD_AREA);
								base->ArchiveTarget = ::As_Target(House->Where_To_Go((FootClass *)base));
							}
							ScenarioInit--;
							return(2);
						}
						ScenarioInit--;
					}
					break;
			}
			break;

		case RTTI_BUILDING:

			if (!House->IsHuman) {

				/*
				**	Find the next available spot to place this newly created building. If the
				**	building could be placed at the desired location, fine. If not, then this
				**	routine will return failure. The calling routine will probably abandon this
				**	building in preference to building another.
				*/
				BaseNodeClass * node = Base.Next_Buildable(((BuildingClass *)base)->Class->Type);
				COORDINATE coord = 0;
				if (node) {
					coord = Cell_Coord(node->Cell);
				} else {

					/*
					**	Find a suitable new spot to place.
					*/
					coord = House->Find_Build_Location((BuildingClass *)base);
				}

				if (coord) {
					if (Flush_For_Placement(base, Coord_Cell(coord))) {
						return(1);
					}
					if (base->Unlimbo(coord)) {
						if (node && ((BuildingClass *)base)->Class->Type == House->BuildStructure) {
							House->BuildStructure = STRUCT_NONE;
						}
						return(2);
					}
				}
			}
			break;

		default:
			break;
	}

	/*
	**	Failure to exit the object results in a false return value.
	*/
	return(0);
}


/***********************************************************************************************
 * BuildingClass::Update_Buildables -- Informs sidebar of additional construction options.     *
 *                                                                                             *
 *    This routine will tell the sidebar of objects that can be built. The function is called  *
 *    whenever a building matures.                                                             *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   11/11/1994 JLB : Created.                                                                 *
 *   12/23/1994 JLB : Only updates for PLAYER buildings.                                       *
 *=============================================================================================*/
void BuildingClass::Update_Buildables(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	/*
	** Only do this for real human players. ST - 3/22/2019 1:38PM
	*/
	if (PlayerPtr != House) {
		if (Session.Type != GAME_GLYPHX_MULTIPLAYER || House->IsHuman == false) {
			return;
		}
	}

	bool buildable_via_capture = (IsCaptured && ActLike != House->ActLike) ? true : false;

	if (!IsInLimbo && Is_Discovered_By_Player()) {
		switch (Class->ToBuild) {
			int i;
			int u;
			int f;
			int a;
			int v;

			case RTTI_VESSELTYPE:
				for (v = VESSEL_FIRST; v < VESSEL_COUNT; v++) {
					if (PlayerPtr->Can_Build(&VesselTypeClass::As_Reference((VesselType)v), ActLike)) {
						if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
							Sidebar_Glyphx_Add(RTTI_VESSELTYPE, v, House, buildable_via_capture);
						} else {
							Map.Add(RTTI_VESSELTYPE, v, buildable_via_capture);
						}
					}
				}
				break;

			case RTTI_BUILDINGTYPE:
				for (i = STRUCT_FIRST; i < STRUCT_COUNT; i++) {
					if (PlayerPtr->Can_Build(&BuildingTypeClass::As_Reference((StructType)i), ActLike)) {
						if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
							Sidebar_Glyphx_Add(RTTI_BUILDINGTYPE, i, House, buildable_via_capture);
						} else {
							Map.Add(RTTI_BUILDINGTYPE, i, buildable_via_capture);
						}
					}
				}
				break;

			case RTTI_UNITTYPE:
				for (u = UNIT_FIRST; u < UNIT_COUNT; u++) {
					if (PlayerPtr->Can_Build(&UnitTypeClass::As_Reference((UnitType)u), ActLike)) {
						if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
							Sidebar_Glyphx_Add(RTTI_UNITTYPE, u, House, buildable_via_capture);
						} else {
							Map.Add(RTTI_UNITTYPE, u, buildable_via_capture);
						}
					}
				}
				break;

			case RTTI_INFANTRYTYPE:
				for (f = INFANTRY_FIRST; f < INFANTRY_COUNT; f++) {
					if (PlayerPtr->Can_Build(&InfantryTypeClass::As_Reference((InfantryType)f), ActLike)) {
						if (InfantryTypeClass::As_Reference((InfantryType)f).IsDog) {
							if (*this == STRUCT_KENNEL) {
								if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
									Sidebar_Glyphx_Add(RTTI_INFANTRYTYPE, f, House, buildable_via_capture);
								} else {
									Map.Add(RTTI_INFANTRYTYPE, f, buildable_via_capture);
								}
							}
						} else {
							if (*this != STRUCT_KENNEL) {
								if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
									Sidebar_Glyphx_Add(RTTI_INFANTRYTYPE, f, House, buildable_via_capture);
								} else {
									Map.Add(RTTI_INFANTRYTYPE, f, buildable_via_capture);
								}
							}
						}
					}
				}
				break;

			case RTTI_AIRCRAFTTYPE:
				for (a = AIRCRAFT_FIRST; a < AIRCRAFT_COUNT; a++) {
					if (PlayerPtr->Can_Build(&AircraftTypeClass::As_Reference((AircraftType)a), ActLike)) {
						if (Session.Type == GAME_GLYPHX_MULTIPLAYER) {
							Sidebar_Glyphx_Add(RTTI_AIRCRAFTTYPE, a, House, buildable_via_capture);
						} else {
							Map.Add(RTTI_AIRCRAFTTYPE, a, buildable_via_capture);
						}
					}
				}
				break;

			default:
				break;
		}
	}
}



#if (0) //Old code for reference. ST - 8/2/2019 2:41PM
/***********************************************************************************************
 * BuildingClass::Update_Buildables -- Informs sidebar of additional construction options.     *
 *                                                                                             *
 *    This routine will tell the sidebar of objects that can be built. The function is called  *
 *    whenever a building matures.                                                             *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   11/11/1994 JLB : Created.                                                                 *
 *   12/23/1994 JLB : Only updates for PLAYER buildings.                                       *
 *=============================================================================================*/
void BuildingClass::Update_Buildables(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (House == PlayerPtr && !IsInLimbo && IsDiscoveredByPlayer) {
		switch (Class->ToBuild) {
			int i;
			int u;
			int f;
			int a;
			int v;

			case RTTI_VESSELTYPE:
				for (v = VESSEL_FIRST; v < VESSEL_COUNT; v++) {
					if (PlayerPtr->Can_Build(&VesselTypeClass::As_Reference((VesselType)v), ActLike)) {
						Map.Add(RTTI_VESSELTYPE, v);
					}
				}
				break;

			case RTTI_BUILDINGTYPE:
				for (i = STRUCT_FIRST; i < STRUCT_COUNT; i++) {
					if (PlayerPtr->Can_Build(&BuildingTypeClass::As_Reference((StructType)i), ActLike)) {
						Map.Add(RTTI_BUILDINGTYPE, i);
					}
				}
				break;

			case RTTI_UNITTYPE:
				for (u = UNIT_FIRST; u < UNIT_COUNT; u++) {
					if (PlayerPtr->Can_Build(&UnitTypeClass::As_Reference((UnitType)u), ActLike)) {
						Map.Add(RTTI_UNITTYPE, u);
					}
				}
				break;

			case RTTI_INFANTRYTYPE:
				for (f = INFANTRY_FIRST; f < INFANTRY_COUNT; f++) {
					if (PlayerPtr->Can_Build(&InfantryTypeClass::As_Reference((InfantryType)f), ActLike)) {
						if (InfantryTypeClass::As_Reference((InfantryType)f).IsDog) {
							if (*this == STRUCT_KENNEL) {
								Map.Add(RTTI_INFANTRYTYPE, f);
							}
						} else {
							if (*this != STRUCT_KENNEL) {
								Map.Add(RTTI_INFANTRYTYPE, f);
							}
						}
					}
				}
				break;

			case RTTI_AIRCRAFTTYPE:
				for (a = AIRCRAFT_FIRST; a < AIRCRAFT_COUNT; a++) {
					if (PlayerPtr->Can_Build(&AircraftTypeClass::As_Reference((AircraftType)a), ActLike)) {
						Map.Add(RTTI_AIRCRAFTTYPE, a);
					}
				}
				break;

			default:
				break;
		}
	}
}
#endif


/***********************************************************************************************
 * BuildingClass::Fire_Out -- Handles when attached animation expires.                         *
 *                                                                                             *
 *    This routine is used to perform any fixups necessary when the attached animation has     *
 *    terminated. This occurs when the fire & smoke animation that a SAM site produces stops.  *
 *    At that point, normal reload procedures can commence.                                    *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   11/30/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Fire_Out(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);
}


/***********************************************************************************************
 * BuildingClass::Limbo -- Handles power adjustment as building goes into limbo.               *
 *                                                                                             *
 *    This routine will handle the power adjustments for the associated house when the         *
 *    building goes into limbo. This means that its power drain or production is subtracted    *
 *    from the house accumulated totals.                                                       *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  bool; Was the building limboed?                                                    *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/24/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
bool BuildingClass::Limbo(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (!IsInLimbo) {

		/*
		**	Update the total factory type, assuming this building has a factory.
		*/
		House->Active_Remove(this);
		House->IsRecalcNeeded = true;
		House->Recalc_Center();

		/*
		**	Update the power status of the owner's house.
		*/
		House->Adjust_Power(-Power_Output());
		House->Adjust_Drain(-Class->Drain);
		House->Adjust_Capacity(-Class->Capacity, true);
		if (House == PlayerPtr) {
			Map.PowerClass::IsToRedraw = true;
			Map.Flag_To_Redraw(false);
		}

		/*
		**	This could be a building that builds. If so, then the sidebar may need adjustment.
		** Set IsInLimbo to true to "fool" the sidebar into knowing that this building
		** isn't available.  Set it back to false so the rest of the Limbo code works.
		** Otherwise, the sidebar won't properly remove non-available buildables.
		*/
//		if (IsOwnedByPlayer && !ScenarioInit) {
//			IsInLimbo = true;
//			Map.Recalc();
//			IsInLimbo = false;
//		}
	}
	return(TechnoClass::Limbo());
}


/***********************************************************************************************
 * BuildingClass::Turret_Facing -- Fetches the turret facing for this building.                *
 *                                                                                             *
 *    This will return the turret facing for this building. Some buildings don't have a        *
 *    visual turret (e.g., pillbox) so they return a turret facing that always faces their     *
 *    current target.                                                                          *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the current facing of the turret.                                     *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
DirType BuildingClass::Turret_Facing(void) const
{
	if (!Class->IsTurretEquipped && Target_Legal(TarCom)) {
		return(::Direction(Center_Coord(), As_Coord(TarCom)));
	}
	return(PrimaryFacing.Current());
}


/***********************************************************************************************
 * BuildingClass::Greatest_Threat -- Searches for target that building can fire upon.          *
 *                                                                                             *
 *    This routine intercepts the Greatest_Threat function so that it can add the ability      *
 *    to search for ground targets, if this isn't a SAM site.                                  *
 *                                                                                             *
 * INPUT:   threat   -- The base threat control value. Typically, it might be THREAT_RANGE     *
 *                      or THREAT_NORMAL.                                                      *
 *                                                                                             *
 * OUTPUT:  Returns with a suitable target. If none could be found, then TARGET_NONE is        *
 *          returned instead.                                                                  *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/01/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
TARGET BuildingClass::Greatest_Threat(ThreatType threat) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (Class->PrimaryWeapon != NULL) {
		threat = threat | Class->PrimaryWeapon->Allowed_Threats();
	}
	if (Class->SecondaryWeapon != NULL) {
		threat = threat | Class->SecondaryWeapon->Allowed_Threats();
	}
	if (House->IsHuman) {
		threat = threat & ~THREAT_BUILDINGS;
	}
	threat = threat | THREAT_RANGE;

//	if (Class->PrimaryWeapon != NULL) {
//		if (Class->PrimaryWeapon->Bullet->IsAntiAircraft) {
//			threat = threat | THREAT_AIR;
//		}
//		if (Class->PrimaryWeapon->Bullet->IsAntiGround) {
//			threat = threat | THREAT_BUILDINGS|THREAT_INFANTRY|THREAT_BOATS|THREAT_VEHICLES;
//		}
//		threat = threat | THREAT_RANGE;
//	}
	return(TechnoClass::Greatest_Threat(threat));
}


/***********************************************************************************************
 * BuildingClass::Grand_Opening -- Handles construction completed special operations.          *
 *                                                                                             *
 *    This routine is called when construction has finished. Typically, this enables           *
 *    new production options for factories.                                                    *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/08/1995 JLB : Created.                                                                 *
 *   06/13/1995 JLB : Added helipad.                                                           *
 *=============================================================================================*/
void BuildingClass::Grand_Opening(bool captured)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (!HasOpened || captured) {
		HasOpened = true;

		/*
		**	Adjust the owning house according to the power, drain, and Tiberium capacity that
		**	this building has.
		*/
		House->Adjust_Drain(Class->Drain);
		House->Adjust_Capacity(Class->Capacity);
		House->IsRecalcNeeded = true;

		/*	SPECIAL CASE:
		**	Tiberium Refineries get a free harvester. Add a harvester to the
		**	reinforcement list at this time.
		*/
		if (*this == STRUCT_REFINERY && !ScenarioInit && !captured && !Debug_Map && (!House->IsHuman || PurchasePrice == 0 || PurchasePrice > Class->Raw_Cost())) {
			CELL cell = Coord_Cell(Adjacent_Cell(Center_Coord(), DIR_S));

			UnitClass * unit = new UnitClass(UNIT_HARVESTER, House->Class->House);
			if (unit != NULL) {

				/*
				**	Try to place down the harvesters. If it could not be placed, then try
				**	to place it in a nearby location.
				*/
				if (!unit->Unlimbo(Cell_Coord(cell), DIR_W)) {
					/*
					**	Check multiple times for clear locations.
					*/
					for (int i = 0; i < 10; i++) {
						cell = unit->Nearby_Location(this, i);
						if (unit->Unlimbo(Cell_Coord(cell), DIR_SW)) {
							break;
						}
					}

					/*
					**	If the harvester could still not be placed, then refund the money
					**	to the owner and then bail.
					*/
					if (unit->IsInLimbo) {
						House->Refund_Money(unit->Class->Cost_Of());
						delete unit;
					}
				}
			} else {

				/*
				**	If the harvester could not be created in the first place, then give
				**	the full refund price to the owning player.
				*/
				House->Refund_Money(UnitTypeClass::As_Reference(UNIT_HARVESTER).Cost_Of());
			}
		}

		/*
		**	Helicopter pads get a free attack helicopter.
		*/
		if (!Rule.IsSeparate && *this == STRUCT_HELIPAD && !captured) {
			ScenarioInit++;
			AircraftClass * air = 0;
			if (House->ActLike == HOUSE_USSR || House->ActLike == HOUSE_BAD || House->ActLike == HOUSE_UKRAINE) {
				air = new AircraftClass(AIRCRAFT_HIND, House->Class->House);
			} else {
				air = new AircraftClass(AIRCRAFT_LONGBOW, House->Class->House);
			}
			if (air) {
				air->Height = 0;
				if (air->Unlimbo(Docking_Coord(), air->Pose_Dir())) {
					air->Assign_Mission(MISSION_GUARD);
					air->Transmit_Message(RADIO_HELLO, this);
					Transmit_Message(RADIO_TETHER);
				}
			}
			ScenarioInit--;
		}
	}
}


/***********************************************************************************************
 * BuildingClass::Repair -- Initiates or terminates the repair process.                        *
 *                                                                                             *
 *    This routine will start, stop, or toggle the repair process. When a building repairs, it *
 *    occurs incrementally over time.                                                          *
 *                                                                                             *
 * INPUT:   control  -- Determines how to control the repair process.                          *
 *                      0: Turns repair process off (if it was on).                            *
 *                      1: Turns repair process on (if it was off).                            *
 *                      -1:Toggles repair process to other state.                              *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/08/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Repair(int control)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	switch (control) {
		case -1:
			IsRepairing = (IsRepairing == false);
			break;

		case 1:
			if (IsRepairing) return;
			IsRepairing = true;
			break;

		case 0:
			if (!IsRepairing) return;
			IsRepairing = false;
			break;

		default:
			break;
	}

	/*
	**	At this point, we know that the repair state has changed. Perform
	**	appropriate action.
	*/
	VocType soundid = VOC_NONE;
	if (IsRepairing) {
		if (Strength == Class->MaxStrength) {
			soundid = VOC_SCOLD;
		} else {
			soundid = VOC_CLICK;
			if (House->IsPlayerControl) {
				Clicked_As_Target(PlayerPtr->Class->House); // 2019/09/20 JAS - Added record of who clicked on the object
			}
			IsWrenchVisible = true;
		}
	} else {
		soundid = VOC_CLICK;
	}
	
	if (House->IsPlayerControl) {
		Sound_Effect(soundid, Coord);
	}
}


/***********************************************************************************************
 * BuildingClass::Sell_Back -- Controls the sell back (demolish) operation.                    *
 *                                                                                             *
 *    This routine will initiate or stop the sell back process for a building. It is called    *
 *    when the player clicks on a building when the sell mode is active.                       *
 *                                                                                             *
 * INPUT:   control  -- The action to perform. 0 = turn deconstruction off, 1 = deconstruct,   *
 *                      -1 = toggle deconstruction state.                                      *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Sell_Back(int control)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (Class->Get_Buildup_Data()) {
		bool decon = false;
		switch (control) {
			case -1:
				decon = (Mission != MISSION_DECONSTRUCTION);
				break;

			case 1:
				if (Mission == MISSION_DECONSTRUCTION) return;
				if (IsGoingToBlow) return;
				decon = true;
				break;

			case 0:
				if (Mission != MISSION_DECONSTRUCTION) return;
				decon = false;
				break;

			default:
				break;
		}

		/*
		**	At this point, we know that the repair state has changed. Perform
		**	appropriate action.
		*/
		if (decon) {
			Assign_Mission(MISSION_DECONSTRUCTION);
			Commence();
			if (House->IsPlayerControl) {
				Clicked_As_Target(PlayerPtr->Class->House);
			}
		}
		if (House->IsPlayerControl) {
			Sound_Effect(VOC_CLICK);
		}
	}
}


/***********************************************************************************************
 * BuildingClass::What_Action -- Determines action to perform if click on specified object.    *
 *                                                                                             *
 *    This routine will determine what action to perform if the mouse was clicked on the       *
 *    object specified. This determination is used to control the mouse imagery and the        *
 *    function process when the mouse button is pressed.                                       *
 *                                                                                             *
 * INPUT:   object   -- Pointer to the object that, if clicked on, will control what action    *
 *                      is to be performed.                                                    *
 *                                                                                             *
 * OUTPUT:  Returns with the ActionType that will occur if the mouse is clicked over the       *
 *          object specified while the building is currently selected.                         *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/18/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
ActionType BuildingClass::What_Action(ObjectClass const * object) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	ActionType action = TechnoClass::What_Action(object);

	if (action == ACTION_SELF) {
		int index;
		if (Class->Is_Factory() && PlayerPtr == House && *House->Factory_Counter(Class->ToBuild) > 1) {
			switch (Class->ToBuild) {
				case RTTI_INFANTRYTYPE:
				case RTTI_INFANTRY:
					action = ACTION_NONE;
					if (*this == STRUCT_KENNEL) {
						for (index = 0; index < Buildings.Count(); index++) {
							BuildingClass *bldg = Buildings.Ptr(index);
							if (bldg != this && bldg->Owner() == Owner() && *bldg == STRUCT_KENNEL) {
								action = ACTION_TOGGLE_PRIMARY;
								break;
							}
						}
					} else {
						for (index = 0; index < Buildings.Count(); index++) {
							BuildingClass *bldg = Buildings.Ptr(index);
							if (bldg != this && bldg->Owner() == Owner() && bldg->Class->ToBuild == RTTI_INFANTRYTYPE && *bldg != STRUCT_KENNEL) {
								action = ACTION_TOGGLE_PRIMARY;
								break;
							}
						}
					}
					break;

				case RTTI_AIRCRAFTTYPE:
				case RTTI_AIRCRAFT:
					action = ACTION_NONE;
					if (*this == STRUCT_AIRSTRIP) {
						for (index = 0; index < Buildings.Count(); index++) {
							BuildingClass *bldg = Buildings.Ptr(index);
							if (bldg != this && bldg->Owner() == Owner() && *bldg == STRUCT_AIRSTRIP) {
								action = ACTION_TOGGLE_PRIMARY;
								break;
							}
						}
					}
					else {
						for (index = 0; index < Buildings.Count(); index++) {
							BuildingClass *bldg = Buildings.Ptr(index);
							if (bldg != this && bldg->Owner() == Owner() && bldg->Class->ToBuild == RTTI_AIRCRAFTTYPE && *bldg != STRUCT_AIRSTRIP) {
								action = ACTION_TOGGLE_PRIMARY;
								break;
							}
						}
					}
					break;

				case RTTI_UNITTYPE:
				case RTTI_UNIT:
				case RTTI_VESSELTYPE:
				case RTTI_VESSEL:
					action = ACTION_TOGGLE_PRIMARY;
					break;

				case RTTI_NONE:
					action = ACTION_NONE;
					break;

				default:
					break;
			}

		} else {
			action = ACTION_NONE;
		}
	}

	/*
	**	Don't allow targeting of SAM sites, even if the CTRL key
	**	is held down. Also don't allow targeting if the object is too
	**	far away.
	*/
	if (action == ACTION_ATTACK && (*this == STRUCT_SAM || *this == STRUCT_AAGUN || !In_Range(object, 0))) {
		action = ACTION_NONE;
	}

	if (action == ACTION_MOVE) {
		action = ACTION_NONE;
	}

	return(action);
}


/***********************************************************************************************
 * BuildingClass::What_Action -- Determines what action will occur.                            *
 *                                                                                             *
 *    This routine examines the cell specified and returns with the action that will be        *
 *    performed if that cell were clicked upon while the building is selected.                 *
 *                                                                                             *
 * INPUT:   cell  -- The cell to examine.                                                      *
 *                                                                                             *
 * OUTPUT:  Returns the ActionType that indicates what should occur if the mouse is clicked    *
 *          on this cell.                                                                      *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/18/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
ActionType BuildingClass::What_Action(CELL cell) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	ActionType action = TechnoClass::What_Action(cell);

	if (action == ACTION_MOVE && (*this != STRUCT_CONST || !Is_MCV_Deploy())) {
		action = ACTION_NONE;
	}

	/*
	**	Don't allow targeting of SAM sites, even if the CTRL key
	**	is held down.
	*/
	if (action == ACTION_ATTACK && Class->PrimaryWeapon != NULL && !Class->PrimaryWeapon->Bullet->IsAntiGround) {
//	if (action == ACTION_ATTACK && (*this == STRUCT_SAM || *this == STRUCT_AAGUN)) {
		action = ACTION_NONE;
	}

	return(action);
}


/***********************************************************************************************
 * BuildingClass::Begin_Mode -- Begins an animation mode for the building.                     *
 *                                                                                             *
 *    This routine will start the building animating. This animation will loop indefinitely    *
 *    until explicitly stopped.                                                                *
 *                                                                                             *
 * INPUT:   bstate   -- The animation state to initiate.                                       *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   The building graphic state will reflect the first stage of this animation the   *
 *             very next time it is rendered.                                                  *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *   07/02/1995 JLB : Uses normalize animation rate where applicable.                          *
 *=============================================================================================*/
void BuildingClass::Begin_Mode(BStateType bstate)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	QueueBState = bstate;
	if (BState == BSTATE_NONE || bstate == BSTATE_CONSTRUCTION || ScenarioInit) {
		BState = bstate;
		QueueBState = BSTATE_NONE;
		BuildingTypeClass::AnimControlType const * ctrl = Fetch_Anim_Control();

		int rate = ctrl->Rate;
		if (Class->IsRegulated && bstate != BSTATE_CONSTRUCTION) {
			rate = Options.Normalize_Delay(rate);
		}
		Set_Rate(rate);
		Set_Stage(ctrl->Start);
	}
}


/***********************************************************************************************
 * BuildingClass::Center_Coord -- Fetches the center coordinate for the building.              *
 *                                                                                             *
 *    This routine is used to set the center coordinate for this building.                     *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the coordinate for the center location for the building.              *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   03/10/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
COORDINATE BuildingClass::Center_Coord(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	return(Coord_Add(Coord, CenterOffset[Class->Size]));
}


/***********************************************************************************************
 * BuildingClass::Docking_Coord -- Fetches the coordinate to use for docking.                  *
 *                                                                                             *
 *    This routine will return the coordinate to use when an object wishes to dock with this   *
 *    building. Normally the docking coordinate would be the center of the building.           *
 *    Exceptions to this would be the airfield and helipad. Their docking coordinates are      *
 *    offset to match the building artwork.                                                    *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the coordinate to head to when trying to dock with this building.     *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   09/21/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
COORDINATE BuildingClass::Docking_Coord(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (*this == STRUCT_HELIPAD) {
		return(Coord_Add(Coord, XYP_COORD(24, 18)));
	}
	if (*this == STRUCT_AIRSTRIP) {
		return(Coord_Add(Coord, XYP_COORD(ICON_PIXEL_W + ICON_PIXEL_W/2, 28)));
	}
	return(TechnoClass::Docking_Coord());
}


/***********************************************************************************************
 * BuildingClass::Can_Fire -- Determines if this building can fire.                            *
 *                                                                                             *
 *    Use this routine to see if the building can fire its weapon.                             *
 *                                                                                             *
 *                                                                                             *
 * INPUT:   target   -- The target that firing upon is desired.                                *
 *                                                                                             *
 *          which    -- Which weapon to use when firing. 0=primary, 1=secondary.               *
 *                                                                                             *
 * OUTPUT:  Returns with the fire possibility code. If firing is allowed, then FIRE_OK is      *
 *          returned. Other cases will result in appropriate fire code value that indicates    *
 *          why firing is not allowed.                                                         *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/03/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
FireErrorType BuildingClass::Can_Fire(TARGET target, int which) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	FireErrorType canfire = TechnoClass::Can_Fire(target, which);

	if (canfire == FIRE_OK) {

		/*
		**	Double check to make sure that the facing is roughly toward
		**	the target. If the difference is too great, then firing is
		**	temporarily postponed.
		*/
		if (Class->IsTurretEquipped) {
			int diff = PrimaryFacing.Difference(Direction(TarCom));
			diff = abs(diff);
			if (ABS(diff) > (*this == STRUCT_SAM ? 64 : 8)) {
//			if (ABS(diff) > 8) {
				return(FIRE_FACING);
			}

			/*
			**	If the turret is rotating then firing must be delayed.
			*/
//			if (PrimaryFacing.Is_Rotating()) {
//				return(FIRE_ROTATING);
//			}
		}

		/*
		**	Certain buildings cannot fire if there is insufficient power.
		*/
		if (Class->IsPowered && House->Power_Fraction() < 1) {
			return(FIRE_BUSY);
		}

		/*
		** If an obelisk can fire, check the state of charge.
		*/
		if (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->IsElectric && !IsCharged) {
			return(FIRE_BUSY);
		}
	}
	return(canfire);
}


/***********************************************************************************************
 * BuildingClass::Toggle_Primary -- Toggles the primary factory state.                         *
 *                                                                                             *
 *    This routine will change the primary factory state of this building. The primary         *
 *    factory is the one that units will be produced from (by default).                        *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Is this building NOW the primary factory?                                          *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/03/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
bool BuildingClass::Toggle_Primary(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (IsLeader) {
		IsLeader = false;
	} else {
		for (int index = 0; index < Buildings.Count(); index++) {
			BuildingClass * building = Buildings.Ptr(index);

			if (!building->IsInLimbo && building->Owner() == Owner() && building->Class->ToBuild == Class->ToBuild) {
				if (Class->ToBuild == RTTI_INFANTRYTYPE) {
					if (*building == STRUCT_KENNEL && *this == STRUCT_KENNEL) {
						building->IsLeader = false;
					} else {
						if (*building != STRUCT_KENNEL && *this != STRUCT_KENNEL) {
							building->IsLeader = false;
						}
					}
				} else if (Class->ToBuild == RTTI_AIRCRAFTTYPE) {
					if (*building == STRUCT_AIRSTRIP && *this == STRUCT_AIRSTRIP) {
						building->IsLeader = false;
					} else {
						if (*building != STRUCT_AIRSTRIP && *this != STRUCT_AIRSTRIP) {
							building->IsLeader = false;
						}
					}
				} else {
					building->IsLeader = false;
				}
			}
		}
		IsLeader = true;
		//
		// MBL 04.20.2020 - Update so that each player in multiplayer will properly hear this when it applies to them
		//
		// if ((HouseClass *)House == PlayerPtr) {
		// 	Speak(VOX_PRIMARY_SELECTED);
		// }
		if ((HouseClass *)House->IsHuman) {
			Speak(VOX_PRIMARY_SELECTED, House);
		}
	}
	Mark(MARK_CHANGE);
	return(IsLeader);
}


/***********************************************************************************************
 * BuildingClass::Captured -- Captures the building.                                           *
 *                                                                                             *
 *    This routine will change the owner of the building. It handles updating any related      *
 *    game systems as a result. Factories are the most prone to have great game related        *
 *    consequences when captured. This could also affect the sidebar and building ownership.   *
 *                                                                                             *
 * INPUT:   newowner -- Pointer to the house that is now the new owner.                        *
 *                                                                                             *
 * OUTPUT:  Was the capture attempt successful?                                                *
 *                                                                                             *
 * WARNINGS:   Capturing could fail if the house is already owned by the one specified or      *
 *             the building isn't allowed to be captured.                                      *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/03/1995 JLB : Created.                                                                 *
 *   07/05/1995 JLB : Fixed production problem with capturing enemy buildings.                 *
 *=============================================================================================*/
bool BuildingClass::Captured(HouseClass * newowner)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (Can_Capture() && newowner != House) {
#ifdef TOFIX
		switch (Owner()) {
			case HOUSE_GOOD:
				Speak(VOX_GDI_CAPTURED);
				break;

			case HOUSE_BAD:
				Speak(VOX_NOD_CAPTURED);
				break;
		}
#endif

		/*
		** Maybe trigger an achivement. ST - 11/14/2019 1:53PM
		*/
		if (newowner->IsHuman) {
			TechnoTypeClass const *object_type = Techno_Type_Class();
			if (object_type) {
				if (newowner->ActLike != House->ActLike) {
					On_Achievement_Event(newowner, "OPPOSING_BUILDING_CAPTURED", object_type->IniName);
				} else {
					On_Achievement_Event(newowner, "BUILDING_CAPTURED", object_type->IniName);
				}	
			}
		}

		/*
		** Make sure the capturer isn't spying on his own building, and if
		** it was a radar facility, update the target house's RadarSpied field.
		*/
		if (SpiedBy & (1<<(newowner->Class->House)) ) {
			SpiedBy -= (1<<(newowner->Class->House));
			if (*this == STRUCT_RADAR) {
				Update_Radar_Spied();
			}
		}

		if (House == PlayerPtr) {
			Map.PowerClass::IsToRedraw = true;
			Map.Flag_To_Redraw(false);
		}

		if (*this == STRUCT_GAP) {
			Remove_Gap_Effect();
			IsJamming = false;
			Arm = 0;
		}

		/*
		** Add this building to the list of buildings captured this game. For internet stats purposes.
		*/
		if (Session.Type == GAME_INTERNET) {
			newowner->CapturedBuildings->Increment_Unit_Total (Class->Type);
		}

		House->Adjust_Power(-Power_Output());
		LastStrength = 0;
		House->Adjust_Drain(-Class->Drain);
		int booty = House->Adjust_Capacity(-Class->Capacity, true);

		/*
		**	If there is something loaded, then it gets captured as well.
		*/
		TechnoClass * tech = Attached_Object();
		if (tech) tech->Captured(newowner);

		/*
		**	If something isn't technically attached, but is sitting on this
		**	building for another reason (e.g., helicopter on helipad), then it
		**	gets captured as well.
		*/
		tech = Contact_With_Whom();
		if (tech) {
			if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER && (::Distance(tech->Center_Coord(), Docking_Coord()) < 0x0040 ||
				(tech->What_Am_I() == RTTI_AIRCRAFT && ((AircraftClass *)tech)->Class->IsFixedWing && ((AircraftClass *)tech)->In_Which_Layer() == LAYER_GROUND)) ) {
				tech->Captured(newowner);
			} else {
				Transmit_Message(RADIO_RUN_AWAY);
				Transmit_Message(RADIO_OVER_OUT);
			}
		}

		/*
		**	Abort any computer production in progress.
		*/
		if (Factory) {
			delete (FactoryClass *)Factory;
			Factory = 0;
		}

		/*
		**	Decrement the factory counter for the original owner.
		*/
		House->Active_Remove(this);

		/*
		**	Flag that both owners now need to update their buildable lists.
		*/
		House->IsRecalcNeeded = true;
		newowner->IsRecalcNeeded = true;
		HouseClass * oldowner = House;
		TARGET tocap = As_Target();

		IsCaptured = true;
		TechnoClass::Captured(newowner);

		oldowner->ToCapture = tocap;
		oldowner->Recalc_Center();
		House->Recalc_Center();
		if (House->ToCapture == As_Target()) {
			House->ToCapture = TARGET_NONE;
		}

		SmudgeType bib;
		CELL cell = Coord_Cell(Coord);
		if (Class->Bib_And_Offset(bib, cell)) {
			SmudgeClass * smudge = new SmudgeClass(bib);
			if (smudge) {
				smudge->Disown(cell);
				delete smudge;
			}
#ifdef FIXIT_CAPTURE_BIB
			if (Session.Type == GAME_NORMAL) {
				new SmudgeClass(bib, Cell_Coord(cell), Class->IsBase ? House->Class->House : HOUSE_NONE);
			} else {
				new SmudgeClass(bib, Cell_Coord(cell), House->Class->House);
			}
#else
			new SmudgeClass(bib, Cell_Coord(cell), House->Class->House);
#endif
		}

		House->Stole(Refund_Amount());

		/*
		**	Increment the factory count for the new owner.
		*/
		House->Active_Add(this);

		IsRepairing = false;
		Grand_Opening(true);
		House->Harvested(booty);

		Mark(MARK_CHANGE);

		/*
		**	Perform a look operation when captured if it was the player
		**	that performed the capture.
		*/
		if (Session.Type == GAME_GLYPHX_MULTIPLAYER && House->IsHuman) {
			Look(false);
		} else {
			if (House == PlayerPtr) {
				Look(false);
			}
		}
		/*
		** If it was spied upon by the player who just captured it, clear the
		** spiedby flag for that house.
		*/
		if (SpiedBy & (1 << (newowner->Class->House))) {
			SpiedBy &= ~(1 << (newowner->Class->House));
		}

		/*
		** Update the new building's colors on the radar map.
		*/
		short const * offset = Occupy_List();
		while (*offset != REFRESH_EOL) {
			CELL cell = Coord_Cell(Coord) + *offset++;
			Map.Radar_Pixel(cell);
		}

		if (oldowner) {
			oldowner->Check_Pertinent_Structures();
		}

		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * BuildingClass::Sort_Y -- Returns the building coordinate used for sorting.                  *
 *                                                                                             *
 *    The coordinate value returned from this function should be used for sorting purposes.    *
 *    It has special offset adjustment applied so that vehicles don't overlap (as much).       *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with a coordinate value suitable to be used for sorting.                   *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/23/1995 JLB : Created.                                                                 *
 *   06/19/1995 JLB : Handles buildings that come with bibs built-in.                          *
 *=============================================================================================*/
COORDINATE BuildingClass::Sort_Y(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (*this == STRUCT_REPAIR) {
		return(Coord);
	}
	if (*this == STRUCT_HELIPAD) {
		return(Center_Coord());
	}
	if (*this == STRUCT_AIRSTRIP) {
		return(Center_Coord());
	}
	if (*this == STRUCT_BARRACKS /*|| *this == STRUCT_POWER*/) {
		return(Center_Coord());
	}
	if (*this == STRUCT_REFINERY) {
		return(Center_Coord());
	}

	/*
	**	Mines need to bias their sort location such that they are typically drawn
	**	before any objects that might overlap them.
	*/
	if (*this == STRUCT_AVMINE || *this == STRUCT_APMINE) {
		return(Coord_Move(Center_Coord(), DIR_N, CELL_LEPTON_H));
	}

	return(Coord_Add(Center_Coord(), XY_Coord(0, (Class->Height()*256)/3)));
}


/***********************************************************************************************
 * BuildingClass::Can_Enter_Cell -- Determines if building can be placed down.                 *
 *                                                                                             *
 *    This routine will determine if the building can be placed down at the location           *
 *    specified.                                                                               *
 *                                                                                             *
 * INPUT:   cell  -- The cell to examine. This is usually the cell of the upper left corner    *
 *                   of the building if it were to be placed down.                             *
 *                                                                                             *
 * OUTPUT:  Returns with the move legality value for placement at the location specified. This *
 *          will either be MOVE_OK or MOVE_NO.                                                 *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
MoveType BuildingClass::Can_Enter_Cell(CELL cell, FacingType) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (*this == STRUCT_CONST && IsDown) {
		return(Map[cell].Is_Clear_To_Build(Class->Speed) ? MOVE_OK : MOVE_NO);
	}

	if (!Debug_Map && ScenarioInit == 0 && Session.Type == GAME_NORMAL && House->IsPlayerControl && !Map[cell].IsMapped) {
		return(MOVE_NO);
	}

	return(Class->Legal_Placement(cell) ? MOVE_OK : MOVE_NO);
}


/***********************************************************************************************
 * BuildingClass::Can_Demolish -- Can the player demolish (sell back) the building?            *
 *                                                                                             *
 *    Determines if the player can sell this building. Selling is possible if the building     *
 *    is not currently in construction or deconstruction animation.                            *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Can the building be demolished at this time?                                       *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *   07/01/1995 JLB : If there is no buildup data, then the building can't be sold.            *
 *   07/17/1995 JLB : Cannot sell a refinery that has a harvester attached.                    *
 *=============================================================================================*/
bool BuildingClass::Can_Demolish(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (Class->IsUnsellable) return(false);

	if (Class->Get_Buildup_Data() && BState != BSTATE_CONSTRUCTION && Mission != MISSION_DECONSTRUCTION && Mission != MISSION_CONSTRUCTION) {
		if (*this == STRUCT_REFINERY && Is_Something_Attached()) return(false);
		return(true);
	}
	return(false);
}


bool BuildingClass::Can_Demolish_Unit(void) const
{
	return((*this == STRUCT_REPAIR || *this == STRUCT_AIRSTRIP) && In_Radio_Contact() && Distance(Contact_With_Whom()) < 0x0080);
}


bool BuildingClass::Can_Capture(void) const
{
	bool can_capture = Class->IsCaptureable && Mission != MISSION_DECONSTRUCTION;

	// Only allow capturing of multiplayer-owned structures
	if (Session.Type != GAME_NORMAL) {
		if (*this == STRUCT_V01) {		// Check to fix exploit in specific map 'Tournament Ore Rift'
			can_capture = false;
		}
	}

	return(can_capture);
}


/***********************************************************************************************
 * BuildingClass::Mission_Guard -- Handles guard mission for combat buildings.                 *
 *                                                                                             *
 *    Buildings that can attack are given this mission. They will wait until a suitable target *
 *    comes within range and then launch into the attack mission. Buildings that have no       *
 *    weaponry will just sit in this routine forever.                                          *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of game frames to delay before this routine will be called *
 *          again.                                                                             *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int BuildingClass::Mission_Guard(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	/*
	**	If this building has a weapon, then search for a target to attack. When
	**	a target is found, switch into attack mode to deal with the threat.
	*/
	if (Is_Weapon_Equipped()) {

		/*
		**	Weapon equipped buildings are ALWAYS ready to launch into another mission if
		**	they are sitting around in guard mode.
		*/
		IsReadyToCommence = true;

		/*
		**	If there is no target available, then search for one.
		*/
		if (!Target_Legal(TarCom)) {
			ThreatType threat = THREAT_NORMAL;
			Assign_Target(Greatest_Threat(threat));
		}

		/*
		**	There is a valid target. Switch into attack mode right away.
		*/
		if (Target_Legal(TarCom)) {
			Assign_Mission(MISSION_ATTACK);
			Commence();
			return(1);
		}
	} else {

		/*
		**	This is the very simple state machine that basically does
		**	nothing. This is the mode that non weapon equipped buildings
		**	are normally in.
		*/
		enum {
			INITIAL_ENTRY,
			IDLE
		};
		switch (Status) {
			case INITIAL_ENTRY:
				Begin_Mode(BSTATE_IDLE);
				Status = IDLE;
				break;

			case IDLE:
				/*
				**	Special case to break out of guard mode if this is a repair
				**	facility and there is a customer waiting at the grease pit.
				*/
				if (*this == STRUCT_REPAIR &&
					In_Radio_Contact() &&
					Contact_With_Whom()->Is_Techno() &&
					((TechnoClass *)Contact_With_Whom())->Mission == MISSION_ENTER &&
					Distance(Contact_With_Whom()) < 0x0040 &&
					Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {

					Assign_Mission(MISSION_REPAIR);
					return(1);
				}
				break;

			default:
				break;
		}

		if (*this == STRUCT_REPAIR) {
			return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
		} else {
			return(MissionControl[Mission].Normal_Delay() * 3 + Random_Pick(0, 2));
		}
	}
	return(MissionControl[Mission].AA_Delay() + Random_Pick(0, 2));
}


/***********************************************************************************************
 * BuildingClass::Mission_Construction -- Handles mission construction.                        *
 *                                                                                             *
 *    This routine will handle mission construction. When this mission is complete, the        *
 *    building will begin normal operation.                                                    *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
 *          again.                                                                             *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int BuildingClass::Mission_Construction(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	enum {
		INITIAL,
		DURING
	};
	switch (Status) {
		case INITIAL:
			Begin_Mode(BSTATE_CONSTRUCTION);
			Transmit_Message(RADIO_BUILDING);
			if (House->IsPlayerControl) {
				Sound_Effect(VOC_CONSTRUCTION, Coord);
			}
			Status = DURING;
			break;

		case DURING:
			if (IsReadyToCommence) {

				/*
				**	When construction is complete, then transmit this
				**	to the construction yard so that it can stop its
				**	construction animation.
				*/
				Transmit_Message(RADIO_COMPLETE);		// "I'm finished."
				Transmit_Message(RADIO_OVER_OUT);		// "You're free."
				Begin_Mode(BSTATE_IDLE);
				Grand_Opening();
				Assign_Mission(MISSION_GUARD);
				PrimaryFacing = Class->StartFace;
			}
			break;

		default:
			break;
	}
	return(1);
}


/***********************************************************************************************
 * BuildingClass::Mission_Deconstruction -- Handles building deconstruction.                   *
 *                                                                                             *
 *    This state machine is only used when the building is deconstructing as a result of       *
 *    selling.  When this mission is finished, the building will no longer exist.              *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of game frames to delay before calling this routine again. *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *   08/13/1995 JLB : Enable selling of units on a repair bay.                                 *
 *   08/20/1995 JLB : Scatters infantry from scattered starting points.                        *
 *=============================================================================================*/
int BuildingClass::Mission_Deconstruction(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	/*
	**	Always force repair off.
	*/
	Repair(0);

	enum {
		INITIAL,
		HOLDING,
		DURING
	};
	switch (Status) {
		case INITIAL:

			/*
			**	Special check for the repair bay which has the ability to sell
			**	whatever is on it. If there is something on the repair bay, then
			**	it will be sold. If there is nothing on the repair bay, then
			**	the repair bay itself will be sold.
			*/
			if (Can_Demolish_Unit() && Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
				TechnoClass * tech = Contact_With_Whom();
				Transmit_Message(RADIO_OVER_OUT);
				if (IsOwnedByPlayer) Speak(VOX_UNIT_SOLD);
				tech->Sell_Back(1);
				Assign_Mission(MISSION_GUARD);
				return(1);
			}

			/*
			** Selling off a shipyard or sub pen may cause attached ships
			** who are repairing themselves to discontinue repairs.
			*/
			if (*this == STRUCT_SHIP_YARD || *this == STRUCT_SUB_PEN) {
				for (int index = 0; index < Vessels.Count(); index++) {
					VesselClass * obj = Vessels.Ptr(index);
					if (obj && !obj->IsInLimbo && obj->House == House) {
						if (obj->IsSelfRepairing) {
							if (::Distance(Center_Coord(), obj->Center_Coord()) < 0x0200) {
								obj->IsSelfRepairing = false;
								obj->IsToSelfRepair = false;
							}
						}
					}
				}
			}

			IsReadyToCommence = false;
			Transmit_Message(RADIO_RUN_AWAY);
			Status = HOLDING;
			break;

		case HOLDING:
			if (!IsTethered) {

				/*
				**	The crew will evacuate from the building. The number of crew
				**	members leaving is equal to the unrecovered cost of the building
				**	divided by 100 (the typical cost of a minigunner infantryman).
				*/
				if (!Target_Legal(ArchiveTarget) || !Is_MCV_Deploy() || *this != STRUCT_CONST) {
					int count = How_Many_Survivors();
					bool engine = false;

					while (count) {

						/*
						**	Ensure that the player only gets ONE engineer and not from a captured
						**	construction yard.
						*/
						InfantryType typ = Crew_Type();
						while (typ == INFANTRY_RENOVATOR && engine) {
							typ = Crew_Type();
						}
						if (typ == INFANTRY_RENOVATOR) engine = true;

						InfantryClass * infantry = 0;
						if (typ != INFANTRY_NONE) infantry = new InfantryClass(typ, House->Class->House);
						if (infantry != NULL) {
							ScenarioInit++;
							COORDINATE coord = Coord_Add(Center_Coord(), XYP_COORD(0, -12));
							coord = Map[coord].Closest_Free_Spot(coord, false);

							if (infantry->Unlimbo(coord, DIR_N)) {
								infantry->IsZoneCheat = infantry->Can_Enter_Cell(Coord_Cell(infantry->Center_Coord())) != MOVE_OK;
								if (infantry->Class->IsNominal) infantry->IsTechnician = true;
								ScenarioInit--;
								infantry->Scatter(0, true);
								ScenarioInit++;
								infantry->Assign_Mission(MISSION_GUARD_AREA);
							} else {
								delete infantry;
							}
							ScenarioInit--;
						}
						count--;
					}
				}

				// MBL 07.10.2020 - In 1v1, sometimes both players will hear this SFX, or neither player will hear it
				// Making it so all players hear it positionally in the map; Per thread discussion in https://jaas.ea.com/browse/TDRA-7245
				//
				#if 0
					if (House->IsPlayerControl) {
						Sound_Effect(VOC_CASHTURN, Coord);
					}
				#else
					Sound_Effect(VOC_CASHTURN, Coord);
				#endif
				
				/*
				**	Destroy all attached objects. ST - 4/24/2020 9:38PM
				*/
				while (Attached_Object()) {
					FootClass * obj = Detach_Object();

					Detach_All(true);
					delete obj;
				}
				
				Transmit_Message(RADIO_OVER_OUT);
				Status = DURING;
				Begin_Mode(BSTATE_CONSTRUCTION);
				IsReadyToCommence = false;
				IsSurvivorless = true;
				break;
			}
			Transmit_Message(RADIO_RUN_AWAY);
			break;

		case DURING:
			if (IsReadyToCommence) {
				House->IsRecalcNeeded = true;

  				// MBL 05.06.2020 - "Structure Sold" is being heard when selecting/moving a redepolyable Con Yard to turn back into an MCV (RA only), so moving below
				#if 0
				// MBL 04.06.2020: Fix being heard by wrong player
				// if (IsOwnedByPlayer) Speak(VOX_STRUCTURE_SOLD);
				if (IsOwnedByPlayer) {
					if ((HouseClass *)House == PlayerPtr) {
						Speak(VOX_STRUCTURE_SOLD);
					}
				}
				#endif
				bool mcv_redeployed = false;

				/*
				**	Construction yards that deconstruct, really just revert back
				**	to an MCV.
				*/
				if (Target_Legal(ArchiveTarget) && *this == STRUCT_CONST && House->IsHuman && Strength > 0) {
					ScenarioInit++;
					UnitClass * unit = new UnitClass(UNIT_MCV, House->Class->House);
					ScenarioInit--;
					if (unit != NULL) {

						/*
						**	Unlimbo the MCV onto the map. The MCV should start in the same
						**	health condition that the construction yard was in.
						*/
						fixed ratio = Health_Ratio();
						int money = Refund_Amount();
						TARGET arch = ArchiveTarget;
						COORDINATE place = Coord_Snap(Adjacent_Cell(Coord, DIR_SE));

						delete this;

						if (unit->Unlimbo(place, DIR_SW)) {
							unit->Strength = (int)unit->Class_Of().MaxStrength * ratio;			// Cast to (int). ST - 5/8/2019

							/*
							**	Lift the move destination from the building and assign
							**	it to the unit.
							*/
							if (Target_Legal(arch)) {
								unit->Assign_Destination(arch);
								unit->Assign_Mission(MISSION_MOVE);
							}

							mcv_redeployed = true;

						} else {

							/*
							**	If, for some strange reason, the MCV could not be placed on the
							**	map, then give the player some money to compensate.
							*/
							House->Refund_Money(money);
						}
					} else {
						House->Refund_Money(Refund_Amount());
						delete this;
					}

				} else {

					/*
					** Selling off a gap generator will cause the cells it affects
					** to stop being jammed.
					*/
					if (*this == STRUCT_GAP) {
						Remove_Gap_Effect();
					}

					/*
					**	A sold building still counts as a kill, but it just isn't directly
					**	attributed to the enemy.
					*/
					WhoLastHurtMe = HOUSE_NONE;
					Record_The_Kill(NULL);

					/*
					**	The player gets part of the money back for the sell.
					*/
					House->Refund_Money(Refund_Amount());
					House->Stole(-Refund_Amount());
					Limbo();

					if (House) {
						House->Check_Pertinent_Structures();
					}

					/*
					**	Finally, delete the building from the game.
					*/
					delete this;
				}

				// MBL 05.06.2020 - "Structure Sold" was being heard when selecting/moving a redepolyable Con Yard to turn back into an MCV (RA only) above, so moved here
				#if 1
				if (!mcv_redeployed) 
				{
					if (IsOwnedByPlayer) {
						if ((HouseClass *)House == PlayerPtr) {
							Speak(VOX_STRUCTURE_SOLD);
						}
					}
				}
				#endif
			}
			break;

		default:
			break;
	}
	return(1);
}


/***********************************************************************************************
 * BuildingClass::Mission_Attack -- Handles attack mission for building.                       *
 *                                                                                             *
 *    Buildings that can attack are processed by this attack mission state machine.            *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
 *          again.                                                                             *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *   02/22/1996 JLB : SAM doesn't lower back into ground.                                      *
 *=============================================================================================*/
int BuildingClass::Mission_Attack(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (*this == STRUCT_SAM) {
		switch (Status) {

			/*
			**	This is the target tracking state of the launcher. It will rotate
			**	to face the current TarCom of the launcher.
			*/
			case SAM_READY:
				if ((Class->IsPowered && House->Power_Fraction() < 1) || IsJammed) {
					return(1);
				}
				if (!Target_Legal(TarCom) || !Is_Target_Aircraft(TarCom) || As_Aircraft(TarCom)->Height == 0) {
					Assign_Target(TARGET_NONE);
					Status = SAM_READY;
					Assign_Mission(MISSION_GUARD);
					Commence();
					return(1);
				} else {
					if (!PrimaryFacing.Is_Rotating()) {
						DirType facing = Direction(TarCom);
						if (PrimaryFacing.Difference(facing)) {
							PrimaryFacing.Set_Desired(facing);
						} else {
							Status = SAM_FIRING;
						}
					}
				}
				return(1);

			/*
			**	The launcher is in the process of firing.
			*/
			case SAM_FIRING:
				if (!Target_Legal(TarCom) || !Is_Target_Aircraft(TarCom) || As_Aircraft(TarCom)->Height == 0) {
					Assign_Target(TARGET_NONE);
					Status = SAM_READY;
				} else {
					FireErrorType error = Can_Fire(TarCom, 0);
					if (error == FIRE_ILLEGAL || error == FIRE_CANT || error == FIRE_RANGE) {
						Assign_Target(TARGET_NONE);
						Status = SAM_READY;
					} else {
						if (error == FIRE_FACING) {
							Status = SAM_READY;
						} else {
							if (error == FIRE_OK) {
								Fire_At(TarCom, 0);
								Fire_At(TarCom, 1);
								Status = SAM_READY;
							}
						}
					}
				}
				return(1);

			default:
				break;
		}
		return(MissionControl[Mission].AA_Delay() + Random_Pick(0, 2));

	}

	if (!Target_Legal(TarCom)) {
		Assign_Target(TARGET_NONE);
		Assign_Mission(MISSION_GUARD);
		Commence();
		return(1);
	}

	int primary = What_Weapon_Should_I_Use(TarCom);
	IsReadyToCommence = true;
	switch (Can_Fire(TarCom, primary)) {
		case FIRE_ILLEGAL:
		case FIRE_CANT:
		case FIRE_RANGE:
		case FIRE_AMMO:
			Assign_Target(TARGET_NONE);
			Assign_Mission(MISSION_GUARD);
			Commence();
			break;

		case FIRE_FACING:
			PrimaryFacing.Set_Desired(Direction(TarCom));
			return(2);

		case FIRE_REARM:
			PrimaryFacing.Set_Desired(Direction(TarCom));
			return(Arm);

		case FIRE_BUSY:
			return(1);

		case FIRE_CLOAKED:
			Do_Uncloak();
			break;

		case FIRE_OK:
			Fire_At(TarCom, primary);
			return(1);

		default:
			break;
	}
	PrimaryFacing.Set_Desired(Direction(TarCom));
	return(1);
//	return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
}


/***********************************************************************************************
 * BuildingClass::Mission_Harvest -- Handles refinery unloading harvesters.                    *
 *                                                                                             *
 *    This state machine handles the refinery when it unloads the harvester.                   *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
 *          again.                                                                             *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int BuildingClass::Mission_Harvest(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	enum {
		INITIAL,					// Dock the Tiberium cannister.
		WAIT_FOR_DOCK,			// Waiting for docking to complete.
		MIDDLE,					// Offload "bails" of tiberium.
		WAIT_FOR_UNDOCK		// Waiting for undocking to complete.
	};
	switch (Status) {
		case INITIAL:
			Status = WAIT_FOR_DOCK;
			break;

		case WAIT_FOR_DOCK:
			if (IsReadyToCommence) {
				IsReadyToCommence = false;
				Status = MIDDLE;
			}
			break;

		case MIDDLE:
			if (IsReadyToCommence) {
				IsReadyToCommence = false;

				/*
				**	Force any bib squatters to scatter.
				*/
				Map[Adjacent_Cell(Coord_Cell(Center_Coord()), DIR_S)].Incoming(0, true, true);

				FootClass * techno = Attached_Object();
				if (techno) {
					int bail = techno->Offload_Tiberium_Bail();

					if (bail) {
						House->Harvested(bail);
						if (techno->Tiberium_Load() > 0) {
							return(1);
						}
					}
				}
				Status = WAIT_FOR_UNDOCK;
			}
			break;

		case WAIT_FOR_UNDOCK:
			if (IsReadyToCommence) {

				/*
				**	Detach harvester and go back into idle state.
				*/
				Assign_Mission(MISSION_GUARD);
			}
			break;

		default:
			break;
	}
	return(1);
}


/***********************************************************************************************
 * BuildingClass::Mission_Repair -- Handles the repair (active) state for building.            *
 *                                                                                             *
 *    This state machine is used when the building is active in some sort of repair or         *
 *    construction mode. The construction yard will animate. The repair facility will repair   *
 *    anything that it docked on it.                                                           *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of game frames to delay before calling this routine again. *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *   06/25/1995 JLB : Handles repair facility                                                  *
 *   07/29/1995 JLB : Repair rate is controlled by power rating.                               *
 *=============================================================================================*/
int BuildingClass::Mission_Repair(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (*this == STRUCT_CONST) {
		enum {
			INITIAL,
			DURING
		};
		switch (Status) {
			case INITIAL:
				Begin_Mode(BSTATE_ACTIVE);
				Status = DURING;
				break;

			case DURING:
				if (!In_Radio_Contact()) {
					Assign_Mission(MISSION_GUARD);
				}
				break;

			default:
				break;
		}
		return(1);
	}

	if (*this == STRUCT_REPAIR) {
		enum {
			INITIAL,
			IDLE,
			DURING
		};
		switch (Status) {
			case INITIAL:
				{
					if (!In_Radio_Contact()) {
						Begin_Mode(BSTATE_IDLE);
						Assign_Mission(MISSION_GUARD);
						return(1);
					}
					IsReadyToCommence = false;
					int distance = 0x10;
					TechnoClass *tech = Contact_With_Whom();

					/*
					** BG: If the unit to repair is an aircraft, and the aircraft is
					** fixed-wing, and it's landed, be much more liberal with the
					** distance check.  Fixed-wing aircraft are very inaccurate with
					** their landings.
					*/
					if (tech->What_Am_I() == RTTI_AIRCRAFT) {
						if ( ((AircraftClass *)tech)->Class->IsFixedWing &&
							((AircraftClass *)tech)->In_Which_Layer() == LAYER_GROUND) {
							distance = 0x80;
						}
					}
					if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER && Distance(Contact_With_Whom()) < distance) {
						Status = IDLE;
						return(TICKS_PER_SECOND/4);
					}
					break;
				}

			case IDLE:
				if (!In_Radio_Contact()) {
					Assign_Mission(MISSION_GUARD);
					return(1);
				}

				if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
					TechnoClass * radio = Contact_With_Whom();

					if ( ((radio->Health_Ratio() < Rule.ConditionGreen) ||
						   (radio->What_Am_I() == RTTI_UNIT && *(UnitClass *)radio == UNIT_MINELAYER))
							&& Transmit_Message(RADIO_REPAIR) == RADIO_ROGER) {

						/*
						**	If the object over the repair bay is marked as useless, then
						**	sell it back to get some money.
						*/
						if (radio->IsUseless) {
							if (!radio->House->IsHuman) {
								radio->Sell_Back(1);
							}
							Status = INITIAL;
							IsReadyToCommence = true;
						} else {

							//
							// MBL 04.27.2020: Legacy VOX_REPAIRING seems to be never called in TD, but only in RA.
							// It is currently supported as a client GUI event when standard repairing begins, with "REPAIR1" on both TD and RA
							//
							// This repairing is in reference to the repair bay
							// There is a newer bug (https://jaas.ea.com/browse/TDRA-6224) reporting that it is heard in multiplayer by 
							// other players, from this call, so modifiying the original call here:
							//
							// if (IsOwnedByPlayer) Speak(VOX_REPAIRING);
							if (IsOwnedByPlayer) Speak(VOX_REPAIRING, House);

							Status = DURING;
							Begin_Mode(BSTATE_ACTIVE);
							IsReadyToCommence = false;
						}
					} else {
//						Transmit_Message(RADIO_RUN_AWAY);
///*BG*/					if(radio->Health_Ratio() >= Rule.ConditionGreen) {
//								Transmit_Message(RADIO_RUN_AWAY);
//							}
					}
				}
				break;

			case DURING:
				if (!In_Radio_Contact()) {
					Begin_Mode(BSTATE_IDLE);
					Status = IDLE;
					return(1);
				}

				/*
				**	Check to see if the repair light blink has completed and the attached
				**	unit is not doing something else. If these conditions are favorable,
				**	the repair can proceed another step.
				*/
				if (IsReadyToCommence && Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER) {
					IsReadyToCommence = false;

					/*
					**	Tell the attached unit to repair one step. It will respond with how
					**	it fared.
					*/
					switch (Transmit_Message(RADIO_REPAIR)) {

						/*
						**	The repair step proceeded smoothly. Proceed normally with the
						**	repair process.
						*/
						case RADIO_ROGER:
							break;

						/*
						**	The repair operation was aborted because of some reason. Presume
						**	that the reason is because of low cash.
						*/
						case RADIO_CANT:
							if (IsOwnedByPlayer) Speak(VOX_NO_CASH);
							Begin_Mode(BSTATE_IDLE);
							Status = IDLE;
							break;

						/*
						**	The repair step resulted in a completely repaired unit.
						*/
						case RADIO_ALL_DONE:

							// MBL 04.27.2020: Make only audible to the correct player
							// if (IsOwnedByPlayer) Speak(VOX_UNIT_REPAIRED);
							if (IsOwnedByPlayer) Speak(VOX_UNIT_REPAIRED, House);

//							Transmit_Message(RADIO_RUN_AWAY);
							Begin_Mode(BSTATE_IDLE);
							Status = IDLE;
							break;

						/*
						**	The repair step could not be completed because this unit is already
						**	at full strength.
						*/
						case RADIO_NEGATIVE:
						default:
//							Transmit_Message(RADIO_RUN_AWAY);
							Begin_Mode(BSTATE_IDLE);
							Status = IDLE;
							break;

					}
				}
				return(1);

			default:
				break;
		}
		return(MissionControl[Mission].Normal_Delay());
	}

	if (*this == STRUCT_HELIPAD || *this == STRUCT_AIRSTRIP) {
		enum {
			INITIAL,
			DURING
		};
		switch (Status) {
			case INITIAL:
				if (Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_ROGER && Transmit_Message(RADIO_PREPARED) == RADIO_NEGATIVE) {
					Begin_Mode(BSTATE_ACTIVE);
					Contact_With_Whom()->Assign_Mission(MISSION_SLEEP);
					Status = DURING;
					return(1);
				}
				Assign_Mission(MISSION_GUARD);
				break;

			case DURING:
				if (IsReadyToCommence) {
					if (!In_Radio_Contact() || Transmit_Message(RADIO_NEED_TO_MOVE) == RADIO_NEGATIVE) {
						Assign_Mission(MISSION_GUARD);
						return(1);
					}

					if (Transmit_Message(RADIO_PREPARED) == RADIO_ROGER) {
						Contact_With_Whom()->Assign_Mission(MISSION_GUARD);
						Assign_Mission(MISSION_GUARD);
						return(1);
					}

					if (Transmit_Message(RADIO_RELOAD) != RADIO_ROGER) {
						Assign_Mission(MISSION_GUARD);
						Contact_With_Whom()->Assign_Mission(MISSION_GUARD);
						return(1);
					} else {
						fixed pfrac = Saturate(House->Power_Fraction(), 1);
						if (pfrac < fixed::_1_2) pfrac = fixed::_1_2;
						int time = Inverse(pfrac) * Rule.ReloadRate * TICKS_PER_MINUTE;
//						int time = Bound((int)(TICKS_PER_SECOND * Saturate(House->Power_Fraction(), 1)), 0, TICKS_PER_SECOND);
//						time = (TICKS_PER_SECOND*3) - time;
						IsReadyToCommence = false;
						return(time);
					}
				}
				break;

			default:
				break;
		}
		return(3);
	}
	return(TICKS_PER_SECOND);
}


/***********************************************************************************************
 * BuildingClass::Mission_Missile -- State machine for nuclear missile launch.                 *
 *                                                                                             *
 *    This handles the Temple of Nod launching its nuclear missile.                            *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of frames to delay before calling this routine again.      *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/04/1995 JLB : Commented.                                                               *
 *=============================================================================================*/
int BuildingClass::Mission_Missile(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (*this == STRUCT_ADVANCED_TECH) {
		enum {
			DOOR_OPENING,
			LAUNCH_UP,
			SATELLITE_DEPLOY,
			DONE_LAUNCH
		};

		switch (Status) {

			/*
			** The initial case is responsible for starting the door
			** opening on the building, the missile rising, and smoke broiling.
			*/
			case DOOR_OPENING:
				{
#ifdef FIXIT_VERSION_3
					COORDINATE door = Coord_Move(Center_Coord(), (DirType)0xC0, 0x30);
					AnimClass * sput = new AnimClass(ANIM_SPUTDOOR, door);
					if (sput) {
						IsReadyToCommence = false;
						Status = LAUNCH_UP;
						AnimToTrack = sput->As_Target();
					}
#else
					IsReadyToCommence = false;
					COORDINATE door = Coord_Move(Center_Coord(), (DirType)0xC0, 0x30);
					AnimClass * sput = new AnimClass(ANIM_SPUTDOOR, door);
					Status = LAUNCH_UP;
					AnimToTrack = sput->As_Target();
					return(1);
#endif
				}

			/*
			** Once the smoke has been going for a little while this
			** actually handles launching the missile into the air.
			*/
			case LAUNCH_UP:
				{
					AnimClass * sput = As_Animation(AnimToTrack);
					if (sput) {
						if (sput->Fetch_Stage() >= 19) {
							CELL center = Coord_Cell(Center_Coord());
							CELL cell = XY_Cell( Cell_X(center), 1);
							TARGET targ = ::As_Target(cell);

							BulletClass * bullet = new BulletClass(BULLET_GPS_SATELLITE, targ, this, 200, WARHEAD_FIRE, MPH_ROCKET);
							if (bullet) {
								COORDINATE launch = Coord_Move(Center_Coord(), (DirType)0xC0, 0x30);
								if (!bullet->Unlimbo(launch, DIR_N)) {
									delete bullet;
									bullet = NULL;
								}
							}

							if (bullet) {
								Assign_Mission(MISSION_GUARD);
							}
						}
					}
				}
				return(1);
		}
	}

	if (*this == STRUCT_MSLO) {
		enum {
			INITIAL,
			DOOR_OPENING,
			LAUNCH_UP,
			LAUNCH_DOWN,
			DONE_LAUNCH
		};

		switch (Status) {

			/*
			** The initial case is responsible for starting the door
			** opening on the building.
			*/
			case INITIAL:
				IsReadyToCommence = false;
				Begin_Mode(BSTATE_ACTIVE);	// open the door
				Status = DOOR_OPENING;
				return(1);

			/*
			** This polls for the case when the door is actually open and
			** then kicks off the missile smoke.
			*/
			case DOOR_OPENING:
				if (IsReadyToCommence) {
					Begin_Mode(BSTATE_AUX1);	// hold the door open
					Status = LAUNCH_UP;
					return(14);
				}
				return(1);

			/*
			** Once the smoke has been going for a little while this
			** actually handles launching the missile into the air.
			*/
			case LAUNCH_UP:
				{
					CELL center = Coord_Cell(Center_Coord());
					CELL cell = XY_Cell( Cell_X(center), 1);
					TARGET targ = ::As_Target(cell);
					BulletClass * bullet = new BulletClass(BULLET_NUKE_UP, targ, this, 200, WARHEAD_HE, MPH_VERY_FAST);
					if (bullet) {
						COORDINATE launch = Coord_Move(Center_Coord(), (DirType)28, 0xA0);
						if (!bullet->Unlimbo(launch, DIR_N)) {
							delete bullet;
							bullet = NULL;
						}
					}

					if (bullet) {
						Speak(VOX_ABOMB_LAUNCH);
						Status = LAUNCH_DOWN;
						/*
						** Hack: If it's the artificial nukes, don't let the bullets come down (as
						** they're the only ones that blow up).  We know it's artificial if you're
						** at tech level 10 or below, because you can't build the nuclear silo until
						** tech level 15 or so.
						*/
						if (House->Control.TechLevel <= 10) {
							return(6);
						}
						bullet = new BulletClass(BULLET_NUKE_DOWN, ::As_Target(House->NukeDest), this, 200, WARHEAD_NUKE, MPH_VERY_FAST);
						if (bullet) {
							int celly = Cell_Y(House->NukeDest);
							celly -= 64;
							if (celly < 1) celly = 1;
							COORDINATE start = Cell_Coord(XY_Cell(Cell_X(House->NukeDest), celly));
							if (!bullet->Unlimbo(start, DIR_S)) {
								delete bullet;
							}
						}
						return(8 * TICKS_PER_SECOND);
					}
				}
				return(1);

			/*
			** Once the missile is in the air, this handles waiting for
			** the missile to be off the screen and then launching one down
			** over the target.
			*/
			case LAUNCH_DOWN:
				{
					Begin_Mode(BSTATE_AUX2);	// start the door closing

#ifdef OBSOLETE
					/*
					** Hack: If it's the artificial nukes, don't let the bullets come down (as
					** they're the only ones that blow up).  We know it's artificial if you're
					** at tech level 10 or below, because you can't build the nuclear silo until
					** tech level 15 or so.
					*/
					if (House->Control.TechLevel <= 10) {
						Status = DONE_LAUNCH;
						return(6);
					}
					BulletClass * bullet = new BulletClass(BULLET_NUKE_DOWN, ::As_Target(House->NukeDest), this, 200, WARHEAD_NUKE, MPH_VERY_FAST);
					if (bullet) {
						int celly = Cell_Y(House->NukeDest);
						celly -= 15;
						if (celly < 1) celly = 1;
						COORDINATE start = Cell_Coord(XY_Cell(Cell_X(House->NukeDest), celly));
						if (!bullet->Unlimbo(start, DIR_S)) {
							delete bullet;
						}
					}
					if (bullet) {
#endif
						Status = DONE_LAUNCH;
						return(6);
					}
#ifdef OBSOLETE
				}
				return(1);
#endif

			/*
			** Once the missile is done launching this handles allowing
			** the building to sit there with its door closed.
			*/
			case DONE_LAUNCH:
				Begin_Mode(BSTATE_IDLE);	// keep the door closed.
				Assign_Mission(MISSION_GUARD);
				return(60);
		}
	}
	return(MissionControl[Mission].Normal_Delay());
}


/***********************************************************************************************
 * BuildingClass::Revealed -- Reveals the building to the specified house.                     *
 *                                                                                             *
 *    This routine will reveal the building to the specified house. It will handle updating    *
 *    the sidebar for player owned buildings. A player owned building that hasn't been         *
 *    revealed, is in a state of pseudo-limbo. It cannot be used for any of its special        *
 *    abilities even though it exists on the map for all other purposes.                       *
 *                                                                                             *
 * INPUT:   house -- The house that this building is being revealed to.                        *
 *                                                                                             *
 * OUTPUT:  Was this building revealed by this procedure?                                      *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
bool BuildingClass::Revealed(HouseClass * house)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (TechnoClass::Revealed(house)) {

		if (!ScenarioInit) {
			House->JustBuiltStructure = Class->Type;
			House->IsBuiltSomething = true;
		}
		House->IsRecalcNeeded = true;

		/*
		**	Perform any grand opening here so that in the scenarios where a player
		**	owned house is not yet revealed, it won't be reflected in the sidebar
		**	selection icons.
		*/
		if (!In_Radio_Contact() && House->IsHuman && Mission != MISSION_CONSTRUCTION) {
			Grand_Opening();
		} else {
			if (!In_Radio_Contact() && !House->IsHuman && house == House && Mission != MISSION_CONSTRUCTION) {
				Grand_Opening();
			}
		}

		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * BuildingClass::Enter_Idle_Mode -- The building will enter its idle mode.                    *
 *                                                                                             *
 *    This routine is called when the exact mode of the building isn't known. By examining     *
 *    the building's condition, this routine will assign an appropriate mission.               *
 *                                                                                             *
 * INPUT:   initial  -- This this being called during scenario init?                           *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/25/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Enter_Idle_Mode(bool initial)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	/*
	**	Assign an appropriate mission for the building. If the ScenarioInit flag is true, then
	**	this must be an initial building. Start such buildings in idle state. For other buildings
	**	it indicates that it is being placed during game play and thus it must start in
	**	the "construction" mission.
	*/
	MissionType mission = MISSION_GUARD;


	if (!initial || ScenarioInit || Debug_Map) {
		Begin_Mode(BSTATE_IDLE);
		mission = MISSION_GUARD;
	} else {
		Begin_Mode(BSTATE_CONSTRUCTION);
		mission = MISSION_CONSTRUCTION;
	}
	Assign_Mission(mission);
}


/***********************************************************************************************
 * BuildingClass::Pip_Count -- Determines "full" pips to display for building.                 *
 *                                                                                             *
 *    This routine will determine the number of pips that should be filled in when rendering   *
 *    the building.                                                                            *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns the number of pips to display as filled in.                                *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   06/28/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int BuildingClass::Pip_Count(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	return(Class->Max_Pips() * House->Tiberium_Fraction());
}


/***********************************************************************************************
 * BuildingClass::Death_Announcement -- Announce the death of this building.                   *
 *                                                                                             *
 *    This routine is called when the building is destroyed by "unnatural" means. Typically    *
 *    as a result of combat. If the building is known to the player, then it should be         *
 *    announced.                                                                               *
 *                                                                                             *
 * INPUT:   source   -- The object most directly responsible for the building's death.         *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/04/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Death_Announcement(TechnoClass const * source) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (source != NULL && House->IsPlayerControl) {
		Speak(VOX_STRUCTURE_DESTROYED);
	}
}


/***********************************************************************************************
 * BuildingClass::Fire_Direction -- Fetches the direction of firing.                           *
 *                                                                                             *
 *    This routine will return with the default direction to use when firing from this         *
 *    building. This is the facing of the turret except for the case of non-turret equipped    *
 *    buildings that have a weapon (e.g., guard tower).                                        *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the default firing direction for this building.                       *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/04/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
DirType BuildingClass::Fire_Direction(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (Class->IsTurretEquipped) {
		return(PrimaryFacing.Current());
	}
	return(Direction(TarCom));
}


/***********************************************************************************************
 * BuildingClass::Remap_Table -- Fetches the remap table to use for this building.             *
 *                                                                                             *
 *    Use this routine to fetch the remap table to use.  This override function is needed      *
 *    because the default remap table for techno objects presumes the object is a unit.        *
 *    Buildings aren't units.                                                                  *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the proper remap table to use for this building.                      *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/08/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void const * BuildingClass::Remap_Table(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	return(House->Remap_Table(IsBlushing, Class->Remap));
}


/***********************************************************************************************
 * BuildingClass::Mission_Unload -- Handles the unload mission for a building.                 *
 *                                                                                             *
 *    This is the unload mission for a building. This really only applies to the weapon's      *
 *    factory, since it needs the sophistication of an unload mission due to the door          *
 *    animation.                                                                               *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of game frames to delay before calling this routine        *
 *          again.                                                                             *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int BuildingClass::Mission_Unload(void)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (*this == STRUCT_WEAP) {
		CELL cell = Coord_Cell(Coord) + Class->ExitList[0];
		COORDINATE coord = Cell_Coord(cell);
		CellClass * cellptr = &Map[cell];
		enum {
			INITIAL,
			CLEAR_BIB,
			OPEN,
			LEAVE,
			CLOSE
		};
		enum {
			DOOR_STAGES = 5,
			DOOR_RATE = 8
		};
		UnitClass * unit;
		switch (Status) {
			/*
			**	Start the door opening.
			*/
			case INITIAL:
//				if (cellptr->Cell_Techno()) {
//					cellptr->Incoming(0, true);
//				}
				unit = (UnitClass *)Contact_With_Whom();
				if (unit) {
					unit->Assign_Mission(MISSION_GUARD);
					unit->Commence();
				}
				Open_Door(DOOR_RATE, DOOR_STAGES);
				Status = CLEAR_BIB;
				break;

			/*
			**	Now that the occupants can peek out the door, they will tell
			**	everyone that could be blocking the way, that they should
			**	scatter away.
			*/
			case CLEAR_BIB:
				if (cellptr->Cell_Techno()) {
					cellptr->Incoming(0, true, true);

					/*
					**	Scatter everything around the weapon's factory door.
					*/
					for (FacingType f = FACING_FIRST; f < FACING_COUNT; f++) {
						CellClass * cptr = cellptr->Adjacent_Cell(f);
						if (cptr && cptr->Cell_Building() == NULL) {
							cptr->Incoming(coord, true, true);
						}
					}
				} else {
					Status = OPEN;
				}
				break;

			/*
			**	When the door is finally open and the way is clear, tell the
			**	unit to drive out.
			*/
			case OPEN:
				if (Is_Door_Open()) {
					unit = (UnitClass *)Contact_With_Whom();
					if (unit) {
						unit->Assign_Mission(MISSION_MOVE);

						if (House->IQ >= Rule.IQGuardArea) {
							unit->Assign_Mission(MISSION_GUARD_AREA);
							unit->ArchiveTarget = ::As_Target(House->Where_To_Go(unit));
						}
						unit->Force_Track(DriveClass::OUT_OF_WEAPON_FACTORY, coord);
//						unit->Force_Track(DriveClass::OUT_OF_WEAPON_FACTORY, Adjacent_Cell(Adjacent_Cell(Center_Coord(), FACING_S), FACING_S));
						unit->Set_Speed(128);
						Status = LEAVE;
					} else {
						Close_Door(DOOR_RATE, DOOR_STAGES);
						Status = CLOSE;
					}
				}
				break;

			/*
			**	Wait until the unit has completely left the building.
			*/
			case LEAVE:
				if (!IsTethered) {
					Close_Door(DOOR_RATE, DOOR_STAGES);
					Status = CLOSE;
				} else {

//					if (In_Radio_Contact() && !((FootClass *)Contact_With_Whom())->IsDriving) {
//						Transmit_Message(RADIO_OVER_OUT);
//					}

				}
				break;

			/*
			**	Wait while the door closes.
			*/
			case CLOSE:
				if (Is_Door_Closed()) {
					Enter_Idle_Mode();
				}
				break;

			default:
				break;
		}
		return(MissionControl[Mission].Normal_Delay() + Random_Pick(0, 2));
	}

	Assign_Mission(MISSION_GUARD);
	return(1);
}


/***********************************************************************************************
 * BuildingClass::Power_Output -- Fetches the current power output from this building.         *
 *                                                                                             *
 *    This routine will return the current power output for this building. The power output    *
 *    is adjusted according to the damage level of the building.                               *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns the current power output for this building.                                *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int BuildingClass::Power_Output(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (Class->Power) {
		return(Class->Power * fixed(LastStrength, Class->MaxStrength));
	}
	return(0);
}


/***********************************************************************************************
 * BuildingClass::Detach -- Handles target removal from the game system.                       *
 *                                                                                             *
 *    This routine is called when the specified target is about to be removed from the game    *
 *    system.                                                                                  *
 *                                                                                             *
 * INPUT:   target   -- The target to be removed from this building's targeting computer.      *
 *                                                                                             *
 *          all      -- Is the target about to be completely eliminated?                       *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Detach(TARGET target, bool all)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	TechnoClass::Detach(target, all);
	if (target == WhomToRepay) {
		WhomToRepay = TARGET_NONE;
	}
	if (target == AnimToTrack) {
		AnimToTrack = TARGET_NONE;
	}
}


/***********************************************************************************************
 * BuildingClass::Crew_Type -- This determines the crew that this object generates.            *
 *                                                                                             *
 *    When selling very cheap buildings (such as the silo), a technician will pop out since    *
 *    generating minigunners would be overkill -- the player could use this loophole to        *
 *    gain an advantage.                                                                       *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns the infantry type that this building will generate as a survivor.          *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/05/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
InfantryType BuildingClass::Crew_Type(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	switch (Class->Type) {
		case STRUCT_STORAGE:
			if (Percent_Chance(50)) {
				return(INFANTRY_C1);
			} else {
				return(INFANTRY_C7);
			}

		case STRUCT_CONST:
			if (!IsCaptured && House->IsHuman && Percent_Chance(25)) {
				return(INFANTRY_RENOVATOR);
			}
			break;

		case STRUCT_KENNEL:
			if (Percent_Chance(50)) {
				return(INFANTRY_DOG);
			} else {
				return(INFANTRY_NONE);
			}

		case STRUCT_TENT:
		case STRUCT_BARRACKS:
			return(INFANTRY_E1);

		default:
			break;
	}
	return(TechnoClass::Crew_Type());
}


/***********************************************************************************************
 * BuildingClass::Detach_All -- Possibly abandons production according to factory type.        *
 *                                                                                             *
 *    When this routine is called, it indicates that the building is about to be destroyed     *
 *    or captured. In such a case any production it may be doing, must be abandoned.           *
 *                                                                                             *
 * INPUT:   all   -- Is the object about the be completely destroyed?                          *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/05/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Detach_All(bool all)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	/*
	**	If it is producing something, then it must be abandoned.
	*/
	if (Factory) {
		Factory->Abandon();
		delete (FactoryClass *)Factory;
		Factory = 0;
	}

	/*
	** If the owner HouseClass is building something, and this building can
	** build that thing, we may be the last building for that house that can
	** build that thing; if so, abandon production of it.
	*/
	if (House) {
		FactoryClass * factory = House->Fetch_Factory(Class->ToBuild);

		/*
		**	If a factory was found, then temporarily disable this building and then
		**	determine if any object that is being produced can still be produced. If
		**	not, then the object being produced must be abandoned.
		*/
		if (factory) {
			TechnoClass * object = factory->Get_Object();
			IsInLimbo = true;
			if (object && !object->Techno_Type_Class()->Who_Can_Build_Me(true, false, House->Class->House)) {
				House->Abandon_Production(Class->ToBuild);
			}
			IsInLimbo = false;
		}
	}

	TechnoClass::Detach_All(all);
}


/***********************************************************************************************
 * BuildingClass::Flush_For_Placement -- Handles clearing a zone for object placement.         *
 *                                                                                             *
 *    This routine is used to clear the way for placement of the specified object (usually     *
 *    a building). If there are friendly units blocking the placement area, they are told      *
 *    to scatter. Enemy blocking units are attacked.                                           *
 *                                                                                             *
 * INPUT:   techno   -- Pointer to the object that is desired to be placed.                    *
 *                                                                                             *
 *          cell     -- The cell that placement wants to occur at.                             *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/06/1995 JLB : Created.                                                                 *
 *   09/27/1995 JLB : Revised to use type class function.                                      *
 *=============================================================================================*/
bool BuildingClass::Flush_For_Placement(TechnoClass * techno, CELL cell)
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (techno) {
		return (((BuildingTypeClass const &)techno->Class_Of()).Flush_For_Placement(cell, House));
	}
	return(false);
}


/***********************************************************************************************
 * BuildingClass::Find_Exit_Cell -- Find a clear location to exit an object from this building *
 *                                                                                             *
 *    This routine is called when the building needs to discharge a unit. It will find a       *
 *    nearby (adjacent) cell that is clear enough for the specified object to enter. Typical   *
 *    use of this routine is when the airfield disgorges its cargo.                            *
 *                                                                                             *
 * INPUT:   techno   -- Pointer to the object that wishes to exit this building.               *
 *                                                                                             *
 * OUTPUT:  Returns with the cell number to use for object placement. If no free location      *
 *          could be found, then zero (0) is returned.                                         *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   09/21/1995 JLB : Created.                                                                 *
 *   02/20/1996 JLB : Added default case for exit cell calculation.                            *
 *=============================================================================================*/
CELL BuildingClass::Find_Exit_Cell(TechnoClass const * techno) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	CELL const * ptr;
	CELL origin = Coord_Cell(Coord);

	ptr = Class->ExitList;
	if (ptr != NULL) {
		while (*ptr != REFRESH_EOL) {
			CELL cell = origin + *ptr++;
			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
				return(cell);
			}
		}
	} else {
		int x1, x2;
		int y1, y2;
		CELL cell;

		y1 = -1;
		y2 = Class->Height();
		for (x1 = -1; x1 <= Class->Width(); x1++) {
			cell = origin + x1 + (y1 * MAP_CELL_W);
			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
				return(cell);
			}
			cell = origin + x1 + (y2 * MAP_CELL_W);
			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
				return(cell);
			}
		}

		x1 = -1;
		x2 = Class->Width();
		for (y1 = -1; y1 <= Class->Height(); y1++) {
			cell = origin + (y1 * MAP_CELL_W) + x1;
			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
				return(cell);
			}
			cell = origin + (y1 * MAP_CELL_W) + x2;
			if (Map.In_Radar(cell) && techno->Can_Enter_Cell(cell) == MOVE_OK) {
				return(cell);
			}
		}
	}
	return(0);
}


/***********************************************************************************************
 * BuildingClass::Can_Player_Move -- Can this building be moved?                               *
 *                                                                                             *
 *    This routine answers the question 'can this building be moved?' Typically, only the      *
 *    construction yard can be moved and it does this by undeploying back into a MCV.          *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Can the building move to a new location under player control?                      *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   10/04/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
bool BuildingClass::Can_Player_Move(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	return(*this == STRUCT_CONST && (Mission == MISSION_GUARD) && Special.IsMCVDeploy);
}


/***********************************************************************************************
 * BuildingClass::Exit_Coord -- Determines location where object will leave it.                *
 *                                                                                             *
 *    This routine will return the coordinate where an object that wishes to leave the         *
 *    building will exit at.                                                                   *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the coordinate that the object should be created at.                  *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   02/20/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
COORDINATE BuildingClass::Exit_Coord(void) const
{
	assert(Buildings.ID(this) == ID);
	assert(IsActive);

	if (Class->ExitCoordinate) {
		return(Coord_Add(Coord, Class->ExitCoordinate));
	}
	return(TechnoClass::Exit_Coord());
}


/***********************************************************************************************
 * BuildingClass::Check_Point -- Fetches the landing checkpoint for the given flight pattern.  *
 *                                                                                             *
 *    Use this routine to coordinate a landing operation. The specified checkpoint is          *
 *    converted into a cell number. The landing aircraft should fly over that cell and then    *
 *    request the next check point.                                                            *
 *                                                                                             *
 * INPUT:   cp    -- The check point to convert to a cell number.                              *
 *                                                                                             *
 * OUTPUT:  Returns with the cell that the aircraft should fly over in order to complete       *
 *          that portion of the landing pattern.                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/06/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
CELL BuildingClass::Check_Point(CheckPointType cp) const
{
	CELL xoffset = 6;		// Downwind offset.
	CELL yoffset = 5;		// Crosswind offset.
	CELL cell = Coord_Cell(Center_Coord());

	switch (cp) {
		case CHECK_STACK:
			xoffset = 0;
			break;

		case CHECK_CROSSWIND:
			yoffset = 0;
			break;

		case CHECK_DOWNWIND:
		default:
			break;
	}

	if ((Cell_X(cell) - Map.MapCellX) > Map.MapCellWidth/2)  {
		xoffset = -xoffset;
	}

	if ((Cell_Y(cell) - Map.MapCellY) > Map.MapCellHeight/2)  {
		yoffset = -yoffset;
	}

	return(XY_Cell(Cell_X(cell)+xoffset, Cell_Y(cell)+yoffset));
}


/***********************************************************************************************
 * BuildingClass::Update_Radar_Spied - set house's RadarSpied field appropriately.				  *
 *                                                                                             *
 *    This routine is called when a radar facility is captured or destroyed.  It fills in the  *
 *    RadarSpied field of the house based on whether there's a spied-upon radar facility or not*
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  House->RadarSpied field gets set appropriately.												  *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   03/22/1996 BWG : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Update_Radar_Spied(void)
{
	House->RadarSpied = 0;
	for (int index = 0; index < Buildings.Count(); index++) {
		BuildingClass * obj = Buildings.Ptr(index);
		if (obj && !obj->IsInLimbo && obj->House == House) {
			if (*obj == STRUCT_RADAR /* || *obj == STRUCT_EYE */) {
				House->RadarSpied |= obj->Spied_By();
			}
		}
	}
	Map.RadarClass::Flag_To_Redraw(true);
}


/***********************************************************************************************
 * BuildingClass::Read_INI -- Reads buildings from INI file.                                   *
 *                                                                                             *
 *    This is the basic scenario initialization of building function. It                       *
 *    is called when reading the scenario startup INI file and it handles                      *
 *    creation of all specified buildings.                                                     *
 *                                                                                             *
 *    INI entry format:                                                                        *
 *      Housename, Typename, Strength, Cell, Facing, Triggername                               *
 *                                                                                             *
 * INPUT:   buffer   -- Pointer to the loaded INI file data.                                   *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   05/24/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Read_INI(CCINIClass & ini)
{
	BuildingClass			* b;			// Working unit pointer.
	HousesType				bhouse;		// Building house.
	StructType				classid;		// Building type.
	CELL						cell;			// Cell of building.
	char						buf[128];
	char						* trigname;	// building's trigger's name


	int len = ini.Entry_Count(INI_Name());
	for (int index = 0; index < len; index++) {
		char const * entry = ini.Get_Entry(INI_Name(), index);

		/*
		**	Get a building entry.
		*/
		ini.Get_String(INI_Name(), entry, NULL, buf, sizeof(buf));

		/*
		**	1st token: house name.
		*/
		bhouse = HouseTypeClass::From_Name(strtok(buf, ","));

		/*
		**	2nd token: building name.
		*/
		classid = BuildingTypeClass::From_Name(strtok(NULL, ","));

		if (bhouse != HOUSE_NONE && classid != STRUCT_NONE) {
			int	strength;
			DirType facing;

			/*
			**	3rd token: strength.
			*/
			strength = atoi(strtok(NULL, ","));

			/*
			**	4th token: cell #.
			*/
			cell = atoi(strtok(NULL, ","));

			/*
			**	5th token: facing.
			*/
			facing = (DirType)atoi(strtok(NULL, ","));

			/*
			**	6th token: triggername (can be NULL).
			*/
			trigname = strtok(NULL, ",");

			bool sellable = false;
			char * token_pointer = strtok(NULL, ",");
			if (token_pointer) {
				sellable = atoi(token_pointer);
			}

			bool rebuild = false;
			token_pointer = strtok(NULL, ",");
			if (token_pointer) {
				rebuild = atoi(token_pointer);
			}

			if (HouseClass::As_Pointer(bhouse) != NULL) {
				b = new BuildingClass(classid, bhouse);
				if (b) {

					TriggerTypeClass * tp = TriggerTypeClass::From_Name(trigname);
					if (tp) {
						TriggerClass * tt = Find_Or_Make(tp);
						if (tt) {
							tt->AttachCount++;
							b->Trigger = tt;
						}
					}
					b->IsAllowedToSell = sellable;
					b->IsToRebuild = rebuild;
					b->IsToRepair = rebuild || *b == STRUCT_CONST;

					if (b->Unlimbo(Cell_Coord(cell), facing)) {
						strength = min(strength, 0x100);
						strength = (int)b->Class->MaxStrength * fixed(strength, 256);		// Cast to (int). ST - 5/8/2019
						b->Strength = strength;
						if (b->Strength > b->Class->MaxStrength-3) b->Strength = b->Class->MaxStrength;
						b->IsALemon = false;
					} else {

						/*
						**	If the building could not be unlimboed on the map, then this indicates
						**	a serious error. Delete the building.
						*/
						delete b;
					}
				}
			}
		}
	}
}


/***********************************************************************************************
 * BuildingClass::Write_INI -- Write out the building data to the INI file specified.          *
 *                                                                                             *
 *    This will store the building data (as it relates to scenario initialization) to the      *
 *    INI database specified.                                                                  *
 *                                                                                             *
 * INPUT:   ini   -- Reference to the INI database that the building data will be stored to.   *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/06/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Write_INI(CCINIClass & ini)
{
	/*
	**	First, clear out all existing building data from the ini file.
	*/
	ini.Clear(INI_Name());

	/*
	**	Write the data out.
	*/
	for (int index = 0; index < Buildings.Count(); index++) {
		BuildingClass * building = Buildings.Ptr(index);
		if (!building->IsInLimbo) {
			char	uname[10];
			char	buf[127];

			sprintf(uname, "%d", index);
			sprintf(buf, "%s,%s,%d,%u,%d,%s,%d,%d",
				building->House->Class->IniName,
				building->Class->IniName,
				building->Health_Ratio()*256,
				Coord_Cell(building->Coord),
				building->PrimaryFacing.Current(),
				building->Trigger.Is_Valid() ? building->Trigger->Class->IniName : "None",
				building->IsAllowedToSell,
				building->IsToRebuild
				);
			ini.Put_String(INI_Name(), uname, buf);
		}
	}
}


/***********************************************************************************************
 * BuildingClass::Target_Coord -- Return the coordinate to use when firing on this building.   *
 *                                                                                             *
 *    This routine will determine the "center" location of this building for purposes of       *
 *    targeting. Usually, this location is somewhere near the foundation of the building.      *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the coordinate to use when firing upon this building (or trying to    *
 *          walk onto it).                                                                     *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/19/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
COORDINATE BuildingClass::Target_Coord(void) const
{
	COORDINATE coord = Center_Coord();

	if (Class->FoundationFace != FACING_NONE) {
		return(Adjacent_Cell(coord, Class->FoundationFace));
	}
	return(coord);
}


/***********************************************************************************************
 * BuildingClass::Factory_AI -- Handle factory production and initiation.                      *
 *                                                                                             *
 *    Some building (notably the computer controlled ones) can have a factory object attached. *
 *    This routine handles processing of that factory and also detecting when production       *
 *    should begin in order to initiate production.                                            *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   Only call this routine once per building per game logic loop.                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Factory_AI(void)
{
	/*
	**	Handle any production tied to this building. Only computer controlled buildings have
	**	production attached to the building itself. The player uses the sidebar interface for
	**	all production control.
	*/
	if (Factory.Is_Valid() && Factory->Has_Completed() && PlacementDelay == 0) {
		TechnoClass * product = Factory->Get_Object();
//		FactoryClass * fact = Factory;

		switch (Exit_Object(product)) {

			/*
			**	If the object could not leave the factory, then either request
			**	a transport, place the (what must be a) building using another method, or
			**	abort the production and refund money.
			*/
			case 0:
				Factory->Abandon();
				delete (FactoryClass *)Factory;
				Factory = 0;
				break;

			/*
			**	Exiting this building is prevented by some temporary blockage. Wait
			**	a bit before trying again.
			*/
			case 1:
				PlacementDelay = TICKS_PER_SECOND*3;
				break;

			/*
			**	The object was successfully sent from this factory. Inform the house
			**	tracking logic that the requested object has been produced.
			*/
			case 2:
				switch (product->What_Am_I()) {
					case RTTI_VESSEL:
						House->JustBuiltVessel = ((VesselClass*)product)->Class->Type;
						House->IsBuiltSomething = true;
						break;

					case RTTI_UNIT:
						House->JustBuiltUnit = ((UnitClass*)product)->Class->Type;
						House->IsBuiltSomething = true;
						break;

					case RTTI_INFANTRY:
						House->JustBuiltInfantry = ((InfantryClass*)product)->Class->Type;
						House->IsBuiltSomething = true;
						break;

					case RTTI_BUILDING:
						House->JustBuiltStructure = ((BuildingClass*)product)->Class->Type;
						House->IsBuiltSomething = true;
						break;

					case RTTI_AIRCRAFT:
						House->JustBuiltAircraft = ((AircraftClass*)product)->Class->Type;
						House->IsBuiltSomething = true;
						break;

					default:
						break;
				}
//				fact->Completed();
				Factory->Completed();
//				delete fact;
				delete (FactoryClass *)Factory;
				Factory = 0;
				break;

			default:
				break;
		}
	}

	/*
	**	Pick something to create for this factory.
	*/
	if (House->IsStarted && Mission != MISSION_CONSTRUCTION && Mission != MISSION_DECONSTRUCTION) {

		/*
		**	Buildings that produce other objects have special factory logic handled here.
		*/
		if (Class->ToBuild != RTTI_NONE) {
			if (Factory.Is_Valid()) {

				/*
				**	If production has halted, then just abort production and make the
				**	funds available for something else.
				*/
				if (PlacementDelay == 0 && !Factory->Is_Building()) {
					Factory->Abandon();
					delete (FactoryClass *)Factory;
					Factory = 0;
				}

			} else {

				/*
				**	Only look to start production if there is at least a small amount of
				**	money available. In cases where there is no practical money left, then
				**	production can never complete -- don't bother starting it.
				*/
				if (House->IsStarted && House->Available_Money() > 10) {
					TechnoTypeClass const * techno = House->Suggest_New_Object(Class->ToBuild, *this == STRUCT_KENNEL);

					/*
					**	If a suitable object type was selected for production, then start
					**	producing it now.
					*/
					if (techno != NULL) {
						Factory = new FactoryClass;
						if (Factory.Is_Valid()) {
							if (!Factory->Set(*techno, *House)) {
								delete (FactoryClass *)Factory;
								Factory = 0;
							} else {
								House->Production_Begun(Factory->Get_Object());
								Factory->Start();
							}
						}
					}
				}
			}
		}
	}
}


/***********************************************************************************************
 * BuildingClass::Rotation_AI -- Process any turret rotation required of this building.        *
 *                                                                                             *
 *    Some buildings have a turret and this routine handles processing the turret rotation.    *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   Only call this routine once per building per game logic loop.                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1996 JLB : Created.                                                                 *
 *   10/27/1996 JLB : Rotation does not occur if power and no power avail.                     *
 *=============================================================================================*/
void BuildingClass::Rotation_AI(void)
{
	if (Class->IsTurretEquipped &&
			Mission != MISSION_CONSTRUCTION &&
			Mission != MISSION_DECONSTRUCTION &&
			(!Class->IsPowered || House->Power_Fraction() >= 1)) {

		/*
		**	Rotate turret to match desired facing.
		*/
		if (PrimaryFacing.Is_Rotating()) {
			if (PrimaryFacing.Rotation_Adjust(Class->ROT)) {
				Mark(MARK_CHANGE);
			}
		}
	}
}


/***********************************************************************************************
 * BuildingClass::Charging_AI -- Handles the special charging logic for Tesla coils.           *
 *                                                                                             *
 *    This handles the special logic required of the charging tesla coil. It requires special  *
 *    processing since its charge up is dependant upon the target and power surplus of the     *
 *    owning house.                                                                            *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Charging_AI(void)
{
	if (Class->PrimaryWeapon != NULL && Class->PrimaryWeapon->IsElectric && BState != BSTATE_CONSTRUCTION) {
		if (Target_Legal(TarCom) && House->Power_Fraction() >= 1) {
			if (!IsCharged) {
				if (IsCharging) {
//					if (stagechange) {
						Mark(MARK_CHANGE);
						if (Fetch_Stage() >= 9) {
							IsCharged = true;
							IsCharging = false;
							Set_Rate(0);
						}
//					}
				} else if (!Arm) {
					IsCharged = false;
					IsCharging = true;
					Set_Stage(0);
					Set_Rate(3);
					Sound_Effect(VOC_TESLA_POWER_UP, Coord);
				}
			}
		} else {
			if (IsCharging || IsCharged) {
				Mark(MARK_CHANGE);
				IsCharging = false;
				IsCharged = false;
				Set_Stage(0);
				Set_Rate(0);
			}
		}
	}
}


/***********************************************************************************************
 * BuildingClass::Repair_AI -- Handle the repair (and sell) logic for the building.            *
 *                                                                                             *
 *    This routine handle the repair animation and healing logic. It also detects when the     *
 *    (computer controlled) building should begin repair or sell itself.                       *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   Only call this routine once per building per game logic loop.                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Repair_AI(void)
{
	if (House->IQ >= Rule.IQRepairSell && Mission != MISSION_CONSTRUCTION && Mission != MISSION_DECONSTRUCTION) {
		/*
		**	Possibly start repair process if the building is below half strength.
		*/
//		unsigned ratio = MIN(House->Smartness, 0x00F0);
		if (Can_Repair()) {
			if (House->Available_Money() >= Rule.RepairThreshhold) {
				if (!House->DidRepair) {
					if (!IsRepairing && (IsCaptured || IsToRepair || House->IsHuman || Session.Type != GAME_NORMAL)) {
						House->DidRepair = true;	// flag that this house did its repair allocation for this frame
						Repair(1);

						if (!House->IsHuman) {
							House->RepairTimer = Random_Pick((int)(House->RepairDelay * (TICKS_PER_MINUTE/4)), (int)(House->RepairDelay * TICKS_PER_MINUTE * 2));
						}
					}
				}
			} else {
				if ((Session.Type != GAME_NORMAL || IsAllowedToSell) && IsTickedOff && House->Control.TechLevel >= Rule.IQSellBack && Random_Pick(0, 50) < House->Control.TechLevel && !Trigger.Is_Valid() && *this != STRUCT_CONST && Health_Ratio() < Rule.ConditionRed) {
					Sell_Back(1);
				}
			}
		}
	}

	/*
	**	If it is repairing, then apply any repair effects as necessary.
	*/
	if (IsRepairing && (Frame % (Rule.RepairRate * TICKS_PER_MINUTE)) == 0) {
		IsWrenchVisible = (IsWrenchVisible == false);
		Mark(MARK_CHANGE);
		int cost = Class->Repair_Cost();
		int step = Class->Repair_Step();

		/*
		**	Check for and expend any necessary monies to continue the repair.
		*/
		if (House->Available_Money() >= cost) {
			House->Spend_Money(cost);
			Strength += step;

			if (Strength >= Class->MaxStrength) {
				Strength = Class->MaxStrength;
				IsRepairing = false;
			}
		} else {
			IsRepairing = false;
		}
	}
}


/***********************************************************************************************
 * BuildingClass::Animation_AI -- Handles normal building animation processing.                *
 *                                                                                             *
 *    This will process the general building animation mechanism. It detects when the          *
 *    building animation sequence has completed and flags the building to perform mission      *
 *    changes as a result.                                                                     *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   Call this routine only once per building per game logic loop.                   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   07/29/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Animation_AI(void)
{
	bool stagechange = Graphic_Logic();
	bool toloop = false;

	/*
	**	Always refresh the SAM site if it has an animation change.
	*/
	if (*this == STRUCT_SAM && stagechange) Mark(MARK_CHANGE);

	if ((!Class->IsTurretEquipped && *this != STRUCT_TESLA) || Mission == MISSION_CONSTRUCTION || Mission == MISSION_DECONSTRUCTION) {
		if (stagechange) {

			/*
			**	Check for animation end or if special case of MCV deconstructing when it is allowed
			**	to convert back into an MCV.
			*/
			BuildingTypeClass::AnimControlType const * ctrl = Fetch_Anim_Control();

			/*
			**	When the last frame of the current animation sequence is reached, flag that
			**	a new mission may be started. This must occur before the animation actually
			**	loops so that if a mission change does occur, it will have a chance to change
			**	the building graphic before the last frame is replaced by the first frame of
			**	the loop.
			*/
			if (Fetch_Stage() == ctrl->Start+ctrl->Count-1  || (!Target_Legal(ArchiveTarget) /*Is_MCV_Deploy()*/ && *this == STRUCT_CONST && Mission == MISSION_DECONSTRUCTION && Fetch_Stage() == (42-19))) {
				IsReadyToCommence = true;
			}

			/*
			**	If the animation advances beyond the last frame, then start the animation
			**	sequence over from the beginning.
			*/
			if (Fetch_Stage() >= ctrl->Start+ctrl->Count) {
				toloop = true;
			}
			Mark(MARK_CHANGE);
		} else {
			if (BState == BSTATE_NONE || Fetch_Rate() == 0) {
				IsReadyToCommence = true;
			}
		}
	}

	/*
	**	If there is a door that is animating, then it might cause this building
	**	to be redrawn. Check for and flag to redraw as necessary.
	*/
	if (Time_To_Redraw()) {
		Clear_Redraw_Flag();
		Mark(MARK_CHANGE);
	}

	/*
	**	The animation sequence has looped. Restart it and flag this loop condition.
	**	This is used to tell the mission system that the animation has completed. It
	**	also signals that now is a good time to act on any pending mission.
	*/
	if (toloop) {
		BuildingTypeClass::AnimControlType const * ctrl = Fetch_Anim_Control();
		if (BState == BSTATE_CONSTRUCTION || BState == BSTATE_IDLE) {
			Set_Rate(Options.Normalize_Delay(ctrl->Rate));
		} else {
			Set_Rate(ctrl->Rate);
		}
		Set_Stage(ctrl->Start);
		Mark(MARK_CHANGE);
	}
}


/***********************************************************************************************
 * BuildingClass::How_Many_Survivors -- This determine the maximum number of survivors.        *
 *                                                                                             *
 *    This routine is called to determine how many survivors should run from this building     *
 *    when it is either sold or destroyed. Buildings that are captured have fewer survivors.   *
 *    The number of survivors is a portion of the cost of the building divided by the cost     *
 *    of a minigunner.                                                                         *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the number of soldiers that should run from this building.            *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/04/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
int BuildingClass::How_Many_Survivors(void) const
{
	if (IsSurvivorless || !Class->IsCrew) return(0);

	int divisor = InfantryTypeClass::As_Reference(INFANTRY_E1).Raw_Cost();
	if (divisor == 0) return(0);
	if (IsCaptured) divisor *= 2;
	int count = (Class->Raw_Cost() * Rule.SurvivorFraction) / divisor;
	return(Bound(count, 1, 5));
}


/***********************************************************************************************
 * BuildingClass::Get_Image_Data -- Fetch the image pointer for the building.                  *
 *                                                                                             *
 *    This routine will return with a pointer to the shape data for the building. The shape    *
 *    data is different than normal when the building is undergoing construction and           *
 *    disassembly.                                                                             *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with a pointer to the shape data for this building.                        *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   08/06/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
void const * BuildingClass::Get_Image_Data(void) const
{
	if (BState == BSTATE_CONSTRUCTION) {
		return(Class->Get_Buildup_Data());
	}
	return(TechnoClass::Get_Image_Data());
}


/***********************************************************************************************
 * BuildingClass::Value -- Determine the value of this building.                               *
 *                                                                                             *
 *    The value of the building is normally just its ordinary assigned value. However, in the  *
 *    case of fakes, the value is artificially enhanced to match the structure that is         *
 *    being faked.                                                                             *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  Returns with the point value of the building type.                                 *
 *                                                                                             *
 * WARNINGS:   The point value returned should not be used for scoring, only for target        *
 *             scanning.                                                                       *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   09/16/1996 JLB : Created.                                                                 *
 *=============================================================================================*/
int BuildingClass::Value(void) const
{
	if (Class->IsFake) {
		switch (Class->Type) {
			case STRUCT_FAKEWEAP:
				return(BuildingTypeClass::As_Reference(STRUCT_WEAP).Reward + BuildingTypeClass::As_Reference(STRUCT_WEAP).Risk);

			case STRUCT_FAKECONST:
				return(BuildingTypeClass::As_Reference(STRUCT_CONST).Reward + BuildingTypeClass::As_Reference(STRUCT_CONST).Risk);

			case STRUCT_FAKE_YARD:
				return(BuildingTypeClass::As_Reference(STRUCT_SHIP_YARD).Reward + BuildingTypeClass::As_Reference(STRUCT_SHIP_YARD).Risk);

			case STRUCT_FAKE_PEN:
				return(BuildingTypeClass::As_Reference(STRUCT_SUB_PEN).Reward + BuildingTypeClass::As_Reference(STRUCT_SUB_PEN).Risk);

			case STRUCT_FAKE_RADAR:
				return(BuildingTypeClass::As_Reference(STRUCT_RADAR).Reward + BuildingTypeClass::As_Reference(STRUCT_RADAR).Risk);

			default:
				break;
		}
	}
	return(TechnoClass::Value());
}


/***********************************************************************************************
 * BuildingClass::Remove_Gap_Effect -- Stop a gap generator from jamming cells.					  *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none																										  *
 *                                                                                             *
 * WARNINGS:   																										  *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   09/20/1996 BWG : Created.                                                                 *
 *=============================================================================================*/
void BuildingClass::Remove_Gap_Effect(void)
{
	// unjam this one's field...
	Map.UnJam_From(Coord_Cell(Center_Coord()), Rule.GapShroudRadius, House);
	
	
	/*
	** Updated for client/server multiplayer. ST - 8/12/2019 11:14AM
	*/
	if (Session.Type != GAME_GLYPHX_MULTIPLAYER) {
		if (!House->IsPlayerControl && PlayerPtr->IsGPSActive) {
			Map.Sight_From(Coord_Cell(Center_Coord()), Rule.GapShroudRadius, PlayerPtr);
		}
	
	} else {
		
		for (int i = 0; i < Session.Players.Count(); i++) {
			HouseClass *player_house = HouseClass::As_Pointer(Session.Players[i]->Player.ID);
			if (player_house->IsGPSActive && player_house != House) {
				Map.Sight_From(Coord_Cell(Center_Coord()), Rule.GapShroudRadius, player_house);
			}
		}
	}


	// and rejam any overlapping buildings' fields
	for (int index = 0; index < Buildings.Count(); index++) {
		BuildingClass *obj = Buildings.Ptr(index);
		if (obj && !obj->IsInLimbo && obj->House == House && *obj == STRUCT_GAP && obj!=this) {
			obj->IsJamming = false;
			obj->Arm = 0;
//			Map.Jam_From(Coord_Cell(obj->Center_Coord()), Rule.GapShroudRadius, PlayerPtr);
		}
	}
}


short const * BuildingClass::Overlap_List(bool redraw) const
{
	if ((Spied_By() & (1 << PlayerPtr->Class->House)) != 0 && Is_Selected_By_Player()) {
		if (*this == STRUCT_BARRACKS || *this == STRUCT_TENT) {
			static short const _list[] = {
				-1, 2, (MAP_CELL_W*1)-1, (MAP_CELL_W*1)+2, REFRESH_EOL
			};
			return(_list);
		} else if (*this == STRUCT_REFINERY) {
			static short const _list[] = {
				0, 2, (MAP_CELL_W*2)+0, (MAP_CELL_W*2)+1, (MAP_CELL_W*2)+2, REFRESH_EOL
			};
			return(_list);
		}
	}
	return(TechnoClass::Overlap_List(redraw));
}


unsigned BuildingClass::Spied_By() const
{
	unsigned spiedby = TechnoClass::Spied_By();

	/*
	** If it's an ore refinery or other such storage-capable building,
	** loop thru all of their buildings to see if ANY of them are spied
	** upon, 'cause once you spy any money, you've spied all of it.
	*/
	if (Class->Capacity) {
		for (int index = 0; index < Buildings.Count(); index++) {
			BuildingClass * building = Buildings.Ptr(index);
			if (building->House == House && building->Class->Capacity) {
				spiedby |= building->SpiedBy;
			}
		}
	}

	return spiedby;
}